Project

General

Profile

« Previous | Next » 

Revision 09a0164d

Added by Marcos M 6 months ago

Select an interface IPv6 address based on priority

View differences:

src/etc/inc/interfaces.inc
7593 7593
	}
7594 7594

  
7595 7595
	if ($v6addrs) {
7596
		// use the first IPv6 GUA address if one exists, otherwise the first address
7597
		$v6addr = $v6addrs[array_key_first($v6addrs)];
7596
		// Group IPv6 addresses by their flags
7597
		$address_flags = [
7598
			'linklocal' => [],
7599
			'anycast' => [],
7600
			'tentative' => [],
7601
			'duplicated' => [],
7602
			'detached' => [],
7603
			'deprecated' => [],
7604
			'autoconf' => [],
7605
			'temporary' => [],
7606
			'prefer_source' => [],
7607
			'no_flag' => []
7608
		];
7609
		foreach ($v6addrs as $addrs) {
7610
			$has_flag = false;
7611
			foreach (array_keys($addrs) as $key) {
7612
				if (isset($address_flags[$key])) {
7613
					$has_flag = true;
7614
					$address_flags[$key][] = $addrs['addr'];
7615
				}
7616
			}
7617
			if (!$has_flag) {
7618
				$address_flags['no_flag'][] = $addrs['addr'];
7619
			}
7620
		}
7621

  
7622
		/**
7623
		 * Create a list of IPv6 addresses that prioritizes the most
7624
		 * "valid" source address. Each key in the array references a
7625
		 * group of IPv6 addresses. Each key is assigned the first GUA of
7626
		 * the respective group. If a GUA for the group does not exist,
7627
		 * then the first IPv6 address of the group is assigned.
7628
		 * 
7629
		 * A "preferred" address has the prefer_source flag and does not
7630
		 * have any flags considered "invalid".
7631
		 * 
7632
		 * A "manual" address does not have any flags.
7633
		 * 
7634
		 * A "valid" address does not have any flags considered "invalid".
7635
		 * 
7636
		 * An "invalid" address must have any of the following flags:
7637
		 * deprecated, duplicated, tentative, or detached. It may have
7638
		 * additional flags that need to be considered. The selected
7639
		 * address is based on the following flag order:
7640
		 * prefer_source, temporary, anycast, autoconf, deprecated, duplicated
7641
		 * tentative, and lastly detached.
7642
		 * 
7643
		 * A "linklocal" address has the linklocal flag.
7644
		 */
7645
		$address_priority_list = [
7646
			'preferred' => null,
7647
			'manual' => null,
7648
			'valid' => null,
7649
			'invalid' => null,
7650
			'linklocal' => null
7651
		];
7652
		// The merge/intersect/diff order here is important.
7653
		$candidate_addresses = array_unique(array_merge($address_flags['prefer_source'], $address_flags['no_flag'], $address_flags['temporary'], $address_flags['anycast'], $address_flags['autoconf']));
7654
		$invalid_addresses = array_unique(array_merge($address_flags['deprecated'], $address_flags['duplicated'], $address_flags['tentative'], $address_flags['detached']));
7655
		$invalid_addresses = array_unique(array_merge(array_intersect($candidate_addresses, $invalid_addresses), $invalid_addresses));
7656
		$valid_addresses = array_diff($candidate_addresses, $invalid_addresses);
7657

  
7658
		// Get a preferred address.
7659
		$temp_list = [];
7660
		foreach ($address_flags['prefer_source'] as $address) {
7661
			if (in_array($address, $valid_addresses)) {
7662
				if (is_v6gua($address)) {
7663
					$temp_list = [$address];
7664
					break;
7665
				} else {
7666
					$temp_list[] = $address;
7667
				}
7668
			}
7669
		}
7670
		if (!empty($temp_list)) {
7671
			$address_priority_list['preferred'] = $temp_list[array_key_first($temp_list)];
7672
		}
7673

  
7674
		// Get a manual address.
7675
		$temp_list = [];
7676
		foreach ($address_flags['no_flag'] as $address) {
7677
			if (is_v6gua($address)) {
7678
				$temp_list = [$address];
7679
				break;
7680
			} else {
7681
				$temp_list[] = $address;
7682
			}
7683
		}
7684
		if (!empty($temp_list)) {
7685
			$address_priority_list['manual'] = $temp_list[array_key_first($temp_list)];
7686
		}
7687

  
7688
		// Get a valid address.
7689
		$temp_list = [];
7690
		foreach ($valid_addresses as $address) {
7691
			if (is_v6gua($address)) {
7692
				$temp_list = [$address];
7693
				break;
7694
			} else {
7695
				$temp_list[] = $address;
7696
			}
7697
		}
7698
		if (!empty($temp_list)) {
7699
			$address_priority_list['valid'] = $temp_list[array_key_first($temp_list)];
7700
		}
7701

  
7702
		// Get an invalid address.
7703
		$temp_list = [];
7704
		foreach ($invalid_addresses as $address) {
7705
			if (is_v6gua($address)) {
7706
				$temp_list = [$address];
7707
				break;
7708
			} else {
7709
				$temp_list[] = $address;
7710
			}
7711
		}
7712
		if (!empty($temp_list)) {
7713
			$address_priority_list['invalid'] = $temp_list[array_key_first($temp_list)];
7714
		}
7715

  
7716
		// Get a link-local address
7717
		if (!empty($address_flags['linklocal'])) {
7718
			$address_priority_list['linklocal'] = $address_flags[array_key_first($address_flags['linklocal'])];
7719
		}
7720

  
7721
		$selected_address = null;
7722
		if (isset($address_priority_list['preferred']) && is_v6gua($address_priority_list['preferred'])) {
7723
			$selected_address = $address_priority_list['preferred'];
7724
		} elseif (isset($address_priority_list['manual']) && is_v6gua($address_priority_list['manual'])) {
7725
			$selected_address = $address_priority_list['manual'];
7726
		} elseif (isset($address_priority_list['valid']) && is_v6gua($address_priority_list['valid'])) {
7727
			$selected_address = $address_priority_list['valid'];
7728
		} elseif (isset($address_priority_list['preferred'])) {
7729
			$selected_address = $address_priority_list['preferred'];
7730
		} elseif (isset($address_priority_list['manual'])) {
7731
			$selected_address = $address_priority_list['manual'];
7732
		} elseif (isset($address_priority_list['valid'])) {
7733
			$selected_address = $address_priority_list['valid'];
7734
		} elseif (isset($address_priority_list['invalid'])) {
7735
			$selected_address = $address_priority_list['invalid'];
7736
		} elseif (isset($address_priority_list['linklocal'])) {
7737
			$selected_address = $address_priority_list['linklocal'];
7738
		} else {
7739
			// Unexpected condition
7740
			$v6addr = $v6addrs[array_key_first($v6addrs)];
7741
		}
7742

  
7598 7743
		foreach ($v6addrs as $addr) {
7599
			if (is_v6gua($addr['addr'])) {
7744
			if ($addr['addr'] == $selected_address) {
7600 7745
				$v6addr = $addr;
7601 7746
				break;
7602 7747
			}

Also available in: Unified diff