diff --git a/plist b/plist index c78dad284..78245485b 100644 --- a/plist +++ b/plist @@ -45,6 +45,7 @@ /usr/local/etc/inc/plugins.inc.d/squid.inc /usr/local/etc/inc/plugins.inc.d/suricata.inc /usr/local/etc/inc/plugins.inc.d/unbound.inc +/usr/local/etc/inc/plugins.inc.d/vxlan.inc /usr/local/etc/inc/plugins.inc.d/webgui.inc /usr/local/etc/inc/rrd.inc /usr/local/etc/inc/services.inc @@ -254,6 +255,9 @@ /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/LegacySubsystemController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/KeyPairsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogKeyPair.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php @@ -419,6 +423,10 @@ /usr/local/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php /usr/local/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml /usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/Menu/Menu.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/VxLan.php +/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/VxLan.xml /usr/local/opnsense/mvc/app/models/OPNsense/Monit/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Monit/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/Monit/Migrations/M1_0_0.php @@ -469,6 +477,7 @@ /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/alias_util.volt /usr/local/opnsense/mvc/app/views/OPNsense/IDS/index.volt /usr/local/opnsense/mvc/app/views/OPNsense/IPsec/key_pairs.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Interface/vxlan.volt /usr/local/opnsense/mvc/app/views/OPNsense/Monit/index.volt /usr/local/opnsense/mvc/app/views/OPNsense/Monit/status.volt /usr/local/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index d91df7717..eca191b51 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -904,6 +904,9 @@ function interfaces_configure($verbose = false) /* special interfaces on top of newly generated devices */ $special[] = $if; continue; + } elseif (strstr($ifcfg['if'], 'vxlan.')) { + // XXX device configuration is responsible for interface setup too when trying to init all. + continue; } $is_track6 = !empty($ifcfg['ipaddrv6']) && $ifcfg['ipaddrv6'] == 'track6'; @@ -958,6 +961,7 @@ function interfaces_configure($verbose = false) /* XXX temporary plugin spot */ plugins_configure('ipsec_prepare', $verbose); + plugins_configure('vxlan_prepare', $verbose); interfaces_group_setup(); } diff --git a/src/etc/inc/interfaces.lib.inc b/src/etc/inc/interfaces.lib.inc index 60f34c1fb..4f2b01513 100644 --- a/src/etc/inc/interfaces.lib.inc +++ b/src/etc/inc/interfaces.lib.inc @@ -337,6 +337,17 @@ function legacy_interfaces_details($intf = null) "advbase" => $line_parts[5], "advskew" => $line_parts[7] ); + } elseif (strpos($line, "\tvxlan") !== false) { + if (empty($result[$current_interface]["vxlan"])) { + $result[$current_interface]["vxlan"] = array(); + } + $result[$current_interface]["vxlan"]["vni"] = $line_parts[2]; + $result[$current_interface]["vxlan"]["local"] = $line_parts[4]; + if ($line_parts[5] == "group") { + $result[$current_interface]["vxlan"]["group"] = $line_parts[6]; + } else { + $result[$current_interface]["vxlan"]["remote"] = $line_parts[6]; + } } } diff --git a/src/etc/inc/plugins.inc.d/core.inc b/src/etc/inc/plugins.inc.d/core.inc index 6f3e1b124..4b0a3103a 100644 --- a/src/etc/inc/plugins.inc.d/core.inc +++ b/src/etc/inc/plugins.inc.d/core.inc @@ -129,6 +129,7 @@ function core_devices() $devices[] = array('pattern' => '_stf', 'volatile' => true); $devices[] = array('pattern' => '_wlan', 'volatile' => true); $devices[] = array('pattern' => 'vlan', 'volatile' => true); + $devices[] = array('pattern' => 'vxlan', 'volatile' => true); return $devices; } diff --git a/src/etc/inc/plugins.inc.d/vxlan.inc b/src/etc/inc/plugins.inc.d/vxlan.inc new file mode 100644 index 000000000..39642fc29 --- /dev/null +++ b/src/etc/inc/plugins.inc.d/vxlan.inc @@ -0,0 +1,130 @@ + array('vxlan_configure_interface'), + 'newwanip' => array('vxlan_configure_interface'), + ); + } + + +function vxlan_configure_interface($verbose=false) +{ + $cnf = OPNsense\Core\Config::getInstance()->object(); + $interfaces_details = legacy_interfaces_details(); + $configured_devices = array(); + $changed_devices = array(); + $vxlans = iterator_to_array((new \OPNsense\Interfaces\VxLan())->vxlans->vxlan->iterateItems()); + if ($verbose && !empty($vxlans)) { + echo 'Configuring VXLAN interfaces...'; + flush(); + } + $all_addresses = array(); + $known_addresses = array(); + foreach ($interfaces_details as $intf) { + foreach (['ipv4', 'ipv6'] as $ipproto) { + if (!empty($intf[$ipproto])) { + foreach ($intf[$ipproto] as $net) { + $known_addresses[] = $net['ipaddr']; + } + } + } + } + + // (re)configure vxlan devices + foreach ($vxlans as $vxlan) { + if (!in_array((string)$vxlan->vxlanlocal, $known_addresses)) { + // skip when interface address is not assigned (yet) + continue; + } + $device_name = "vxlan.{$vxlan->deviceId}" ; + $configured_devices[] = $device_name; + $current_settings = array( + "vxlanid" => null, + "vxlanlocal" => null, + "vxlanremote" => null, + "vxlangroup" => null + ); + if (empty($interfaces_details[$device_name])) { + // new device + mwexecf('/sbin/ifconfig vxlan create name %s', array($device_name)); + $isChanged = true; + } else { + $isChanged = false; + $current_settings['vxlanid'] = $interfaces_details[$device_name]['vxlan']['vni']; + $current_settings['vxlanlocal'] = explode(":", $interfaces_details[$device_name]['vxlan']['local'])[0]; + $current_settings['vxlanremote'] = explode(":", $interfaces_details[$device_name]['vxlan']['remote'])[0]; + $current_settings['vxlangroup'] = explode(":", $interfaces_details[$device_name]['vxlan']['group'])[0]; + } + // gather settings, detect changes + $ifcnfcmd = '/sbin/ifconfig %s'; + $ifcnfcmdp = array($device_name); + foreach (array('vxlanid', 'vxlanlocal', 'vxlanremote', 'vxlangroup', 'vxlandev') as $param) { + $value = ''; + if ($param == 'vxlandev') { + $intfnm = (string)$vxlan->$param; + if (!empty($cnf->interfaces->$intfnm)) { + $value = $cnf->interfaces->$intfnm->if->__toString(); + } + } else { + $value = (string)$vxlan->$param; + } + if ($value != '') { + $ifcnfcmd .= " {$param} %s "; + $ifcnfcmdp[] = $value; + } + if (isset($current_settings[$param]) && $current_settings[$param] != $value) { + $isChanged = true; + } + } + if ($isChanged) { + mwexecf($ifcnfcmd, $ifcnfcmdp); + $changed_devices[] = $device_name; + } + } + // destroy non existing interfaces + foreach ($interfaces_details as $intf => $data) { + if (strpos($intf, "vxlan.") === 0) { + if (!in_array($intf, $configured_devices)) { + mwexecf('/sbin/ifconfig %s destroy', array($intf)); + } + } + } + if ($verbose && !empty($vxlans)) { + echo "done.\n"; + } + // configure interface when device has changed + foreach ($changed_devices as $device_name) { + $friendly_if = convert_real_interface_to_friendly_interface_name($device_name); + if (!empty($friendly_if)) { + interface_configure($verbose, $friendly_if); + } + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php new file mode 100644 index 000000000..131fde0e7 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php @@ -0,0 +1,81 @@ +searchBase("vxlans.vxlan", array( + 'enabled', 'deviceId', 'vxlanid', 'vxlanlocal', 'vxlanremote', 'vxlangroup', 'vxlandev' + ), "vxlanid"); + } + + public function setItemAction($uuid) + { + return $this->setBase("vxlan", "vxlans.vxlan", $uuid); + } + + public function addItemAction() + { + return $this->addBase("vxlan", "vxlans.vxlan"); + } + + public function getItemAction($uuid = null) + { + return $this->getBase("vxlan", "vxlans.vxlan", $uuid); + } + + public function delItemAction($uuid) + { + return $this->delBase("vxlans.vxlan", $uuid); + } + + public function toggleItemAction($uuid, $enabled = null) + { + return $this->toggleBase("vxlans.vxlan", $uuid, $enabled); + } + + public function reconfigureAction() + { + $result = array("status" => "failed"); + if ($this->request->isPost()) { + $backend = new Backend(); + $result['status'] = strtolower(trim($backend->configdRun('interface vxlan configure'))); + } + return $result; + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php new file mode 100644 index 000000000..27b2d4922 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php @@ -0,0 +1,38 @@ +view->pick('OPNsense/Interface/vxlan'); + $this->view->formDialogVxlan = $this->getForm("dialogVxlan"); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml new file mode 100644 index 000000000..ba4cc35b6 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml @@ -0,0 +1,49 @@ +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml new file mode 100644 index 000000000..b45e81e37 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml @@ -0,0 +1,9 @@ +| {{ lang._('ID') }} | +{{ lang._('DeviceId') }} | +{{ lang._('VNI') }} | +{{ lang._('Source') }} | +{{ lang._('Commands') }} | +
|---|---|---|---|---|
| + | + + + | +