vxlan6.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. 'use strict';
  2. 'require form';
  3. 'require network';
  4. 'require tools.widgets as widgets';
  5. 'require uci';
  6. network.registerPatternVirtual(/^vxlan-.+$/);
  7. return network.registerProtocol('vxlan6', {
  8. getI18n: function() {
  9. return _('VXLANv6 (RFC7348)');
  10. },
  11. getIfname: function() {
  12. return this._ubus('l3_device') || 'vxlan-%s'.format(this.sid);
  13. },
  14. getOpkgPackage: function() {
  15. return 'vxlan';
  16. },
  17. isFloating: function() {
  18. return true;
  19. },
  20. isVirtual: function() {
  21. return true;
  22. },
  23. getDevices: function() {
  24. return null;
  25. },
  26. containsDevice: function(ifname) {
  27. return (network.getIfnameOf(ifname) == this.getIfname());
  28. },
  29. renderFormOptions: function(s) {
  30. var o;
  31. o = s.taboption('general', form.Value, 'peer6addr', _('Remote IPv6 address'), _('The IPv6 address or the fully-qualified domain name of the remote end.') + '<br/>' +
  32. _('Alternatively, a multicast address to reach a group of peers.') + '<br/>' +
  33. _('Remote VTEP'));
  34. o.optional = false;
  35. o.datatype = 'or(hostname,ip6addr("nomask"))';
  36. o = s.taboption('general', form.Value, 'ip6addr', _('Local IPv6 address'), _('The local IPv6 address over which the tunnel is created (optional).') + '<br/>' +
  37. _('Local VTEP'));
  38. o.optional = true;
  39. o.datatype = 'ip6addr("nomask")';
  40. o = s.taboption('general', form.Value, 'port', _('Destination port'));
  41. o.optional = true;
  42. o.placeholder = 4789;
  43. o.datatype = 'port';
  44. o = s.taboption('general', form.Value, 'srcport', _('Source port range'));
  45. o.optional = true;
  46. o.placeholder = '5000-6000';
  47. o.datatype = 'portrange';
  48. o.load = function(section_id) {
  49. const min = uci.get('network', section_id, 'srcportmin');
  50. const max = uci.get('network', section_id, 'srcportmax');
  51. if (!min || !max)
  52. return null;
  53. return `${min}-${max}`;
  54. };
  55. o.write = function(section_id, value) {
  56. const ports = value?.split('-') || null;
  57. if (ports){
  58. uci.set('network', section_id, 'srcportmin', ports[0]);
  59. uci.set('network', section_id, 'srcportmax', ports[1]);
  60. }
  61. };
  62. o = s.taboption('advanced', form.Value, 'ageing', _('Ageing'),
  63. _('FDB entry lifetime') + '<br/>' +
  64. _('Units: seconds'));
  65. o.optional = true;
  66. o.placeholder = 300;
  67. o.datatype = 'uinteger';
  68. o = s.taboption('advanced', form.Value, 'mtu', _('MTU'),
  69. _('Ensure MTU does not exceed that of parent interface') + '<br/>' +
  70. _('The VXLAN header adds 50 bytes of IPv4 encapsulation overhead, 74 bytes for IPv6.'));
  71. o.optional = true;
  72. o.placeholder = 1280;
  73. o.datatype = 'min(128)';
  74. o = s.taboption('advanced', form.Value, 'maxaddress', _('Max FDB size'),
  75. _('Maximum number of FDB entries'));
  76. o.optional = true;
  77. o.placeholder = 1000;
  78. o.datatype = 'min(1)';
  79. o = s.taboption('general', form.Flag, 'learning', _('Learning'),
  80. _('Automatic mac learning using multicast; inserts unknown source link layer addresses and IP addresses into the VXLAN device %s'
  81. .format('<abbr title="%s">%s</abbr>'.format(_('Forwarding DataBase'), _('FDB')))));
  82. o.optional = true;
  83. o.default = '1';
  84. o.rmempty = false;
  85. o = s.taboption('advanced', form.Flag, 'rsc', _('Route short-circuit (RSC)'),
  86. _('If destination MAC refers to router, replace it with destination MAC address'));
  87. o.optional = true;
  88. o = s.taboption('advanced', form.Flag, 'proxy', _('ARP proxy'),
  89. _('Reply on Neighbour request when mapping found in VXLAN FDB'));
  90. o.optional = true;
  91. o = s.taboption('advanced', form.Flag, 'l2miss', _('l2miss: Layer 2 miss'),
  92. _('On a l2miss, send ARP') + '<br/>' +
  93. _('Emits netlink LLADDR miss notifications') + '<br/>' +
  94. _('Expect netlink reply to add MAC address into VXLAN FDB'));
  95. o.optional = true;
  96. o = s.taboption('advanced', form.Flag, 'l3miss', _('l3miss: Layer 3 miss'),
  97. _('On a l3miss, send ARP for IP -> mac resolution') + '<br/>' +
  98. _('Emits netlink IP ADDR miss notifications') + '<br/>' +
  99. _('Expect netlink reply to add destination IP address into Neighbour table'));
  100. o.optional = true;
  101. o = s.taboption('advanced', form.Flag, 'gbp', _('GBP'),
  102. _('Group Based Policy (VXLAN-GBP) extension'));
  103. o.optional = true;
  104. o = s.taboption('general', form.Value, 'vid', _('VXLAN network identifier'),
  105. _('VNI') + ': ' + _('ID used to uniquely identify the VXLAN'));
  106. o.optional = true;
  107. o.datatype = 'range(1, 16777216)';
  108. o = s.taboption('general', widgets.NetworkSelect, 'tunlink', _('Bind interface'), _('Bind the tunnel to this interface (optional).'));
  109. o.exclude = s.section;
  110. o.nocreate = true;
  111. o.optional = true;
  112. o = s.taboption('advanced', form.Value, 'ttl', _('Override TTL'), _('Specify a TTL (Time to Live) for the encapsulating packet other than the default (64).'));
  113. o.optional = true;
  114. o.placeholder = 64;
  115. o.datatype = 'min(1)';
  116. o = s.taboption('advanced', form.Value, 'tos', _('Override TOS'), _('Specify a TOS (Type of Service).'));
  117. o.optional = true;
  118. // values 0xA0-0xE0 are valid, but don't work
  119. o.value('2', '2: 0x02');
  120. o.value('4', '4: 0x04');
  121. for (var i = 32; i <= 152; i += 8) {
  122. o.value(i, i + ': 0x' + i.toString(16).padStart(2, '0'));
  123. }
  124. o.value('inherit');
  125. o.validate = function(section_id, value) {
  126. if (!value || /^inherit$/.test(value)) return true;
  127. const v = parseInt(value)
  128. if (v % 4 != 0) return false
  129. if (v <= 152 && v > 0)
  130. return true;
  131. return false;
  132. };
  133. o.write = function(section_id, value) {
  134. if (!value) return
  135. value = value === 'inherit' ? value : parseInt(value).toString(16).padStart(2, '0');
  136. return uci.set('network', section_id, 'tos', value);
  137. };
  138. o.load = function(section_id) {
  139. const value = uci.get('network', section_id, 'tos');
  140. return value ? (value === 'inherit' ? value : parseInt(value, 16).toString()) : null;
  141. };
  142. o = s.taboption('advanced', form.Flag, 'rxcsum', _('Enable rx checksum'));
  143. o.optional = true;
  144. o.default = o.enabled;
  145. o = s.taboption('advanced', form.Flag, 'txcsum', _('Enable tx checksum'));
  146. o.optional = true;
  147. o.default = o.enabled;
  148. try {
  149. s.tab('peers', _('Additional Peers'), _('Further information about VXLAN interfaces and peers %s.').format('<a href=\'https://openwrt.org/docs/guide-user/network/tunneling_interface_protocols#protocol_vxlan_vxlan_layer_2_virtualization_over_layer_3_network\'>here</a>'));
  150. }
  151. catch(e) {}
  152. o = s.taboption('peers', form.SectionValue, '_peers', form.GridSection, 'vxlan_peers');
  153. o.depends('proto', 'vxlan');
  154. var ss = o.subsection;
  155. ss.anonymous = true;
  156. ss.addremove = true;
  157. ss.addbtntitle = _('Add peer');
  158. ss.nodescriptions = true;
  159. ss.modaltitle = _('Edit peer');
  160. ss.filter = function(section_id) {
  161. let peer = uci.get('network', section_id);
  162. return (peer.vxlan === s.section ? true: false);
  163. };
  164. o = ss.option(form.Value, 'description', _('Description'), _('Optional. Description of peer.'));
  165. o.placeholder = _('My Peer');
  166. o.datatype = 'string';
  167. o.optional = true;
  168. o = ss.option(form.Value, 'lladr', _('Layer 2 Address'),
  169. _('L2 (MAC) address of peer. Uses source-address learning when %s is specified')
  170. .format('<code>00:00:00:00:00:00</code>'));
  171. o.editable = true;
  172. o.datatype = 'macaddr';
  173. o.optional = true;
  174. o.modalonly = true;
  175. o.value('00:00:00:00:00:00');
  176. o = ss.option(form.Value, 'dst', _('Peer IP'), _('IP address of the remote VXLAN tunnel endpoint where the MAC address (Layer 2 Address) resides or a multicast address for a group of peers.')
  177. + '<br/>' + _('For multicast, an outgoing interface (%s) needs to be specified').format('<code>via</code>'));
  178. o.editable = true;
  179. o.datatype = 'ipaddr';
  180. o.placeholder = '239.1.1.1'
  181. o.rmempty = false;
  182. o.write = function(section_id, value) {
  183. // Note: a heavier alternative is to chain vxlan parameter creation to handleAdd
  184. // but because ipaddr is also mandatory, use this write function
  185. uci.set('network', section_id, 'vxlan', s.section);
  186. return this.super('write', [ section_id, value ]);
  187. };
  188. o = ss.option(form.Value, 'port', _('Port'), _('UDP destination port number to use to connect to the remote VXLAN tunnel endpoint'));
  189. o.editable = true;
  190. o.datatype = 'port';
  191. o.placeholder = 4789;
  192. o.optional = true;
  193. o = ss.option(widgets.NetworkSelect, 'via', _('Via'), _('Name of the outgoing interface to reach the remote VXLAN tunnel endpoint'));
  194. o.editable = true;
  195. o.exclude = s.section;
  196. o.nocreate = true;
  197. o.optional = true;
  198. o.validate = function(section_id, value) {
  199. const dst = this.section.getOption('dst').formvalue(section_id).toLowerCase();
  200. const ipv4MulticastRegex = /^(22[4-9]|23[0-9])(\.\d{1,3}){3}$/;
  201. const ipv6MulticastRegex = /^ff[0-9a-fA-F]{0,2}:.*/;
  202. let isMulticastIP = ipv4MulticastRegex.test(dst) || ipv6MulticastRegex.test(dst);
  203. if (!value && isMulticastIP) {
  204. return _('Via shall be specified when %s is a multicast address'.format(_('Peer IP')));
  205. }
  206. return true;
  207. };
  208. o = ss.option(form.Value, 'vni', _('VNI'), _('the VXLAN Network Identifier (or VXLAN Segment ID) to use to connect to the remote VXLAN tunnel endpoint'));
  209. o.editable = true;
  210. o.datatype = 'range(1, 16777216)';
  211. o.optional = true;
  212. o = ss.option(form.Value, 'src_vni', _('Source VNI'), _('the source VNI Network Identifier (or VXLAN Segment ID) this entry belongs to. Used only when the VXLAN device is in external or collect metadata mode '));
  213. o.editable = true;
  214. o.datatype = 'range(1, 16777216)';
  215. o.optional = true;
  216. }
  217. });