From 15b602b0b786a12b153d0a6eb85d43ff270a4fc5 Mon Sep 17 00:00:00 2001 From: Jon Ludlam Date: Fri, 23 Aug 2013 13:19:47 +0100 Subject: [PATCH] CA-82314: networkd: introduce Linklocal6 IPv6 address mode This commit redefines the IPv6 address mode "None6" to mean "no IPv6 address at all, not even a link local one", and introduces the new mode Linklocal6, which means "only IPv6 address, except a link local one". Previously, it was not possible to get networkd to remove the link-local IPv6 address from an interface. When a link local IPv6 address is requested, it is derived from the interface's MAC address as commonly done. Signed-off-by: Rob Hoes Imported-by: Jon Ludlam --- lib/network_utils.ml | 49 ++++++++++++++++++++++++++++++++++---- networkd/network_server.ml | 10 ++++++++ networkd_db/networkd_db.ml | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/lib/network_utils.ml b/lib/network_utils.ml index f4387bb4f..d61addc2b 100644 --- a/lib/network_utils.ml +++ b/lib/network_utils.ml @@ -234,6 +234,42 @@ info "Found at [ %s ]" (String.concat ", " (List.map string_of_int indices)); Some (ip, prefixlen) with Not_found -> None + (* see http://en.wikipedia.org/wiki/IPv6_address#Modified_EUI-64 *) + let get_ipv6_interface_id dev = + let mac = get_mac dev in + let bytes = List.map (fun byte -> int_of_string ("0x" ^ byte)) (String.split ':' mac) in + let rec modified_bytes ac i = function + | [] -> + ac + | head :: tail -> + if i = 0 then + let head' = head lxor 2 in + modified_bytes (head' :: ac) 1 tail + else if i = 2 then + modified_bytes (254 :: 255 :: head :: ac) 3 tail + else + modified_bytes (head :: ac) (i + 1) tail + in + let bytes' = List.rev (modified_bytes [] 0 bytes) in + [0; 0; 0; 0; 0; 0; 0; 0] @ bytes' + + let get_ipv6_link_local_addr dev = + let id = get_ipv6_interface_id dev in + let link_local = 0xfe :: 0x80 :: (List.tl (List.tl id)) in + let rec to_string ac i = function + | [] -> ac + | hd :: tl -> + let separator = + if i = 0 || i mod 2 = 1 then + "" + else + ":" + in + let ac' = ac ^ separator ^ Printf.sprintf "%02x" hd in + to_string ac' (i + 1) tl + in + to_string "" 0 link_local ^ "/64" + let get_ipv4 dev = let addrs = addr dev "inet" in List.filter_map split_addr addrs @@ -254,13 +290,16 @@ info "Found at [ %s ]" (String.concat ", " (List.map string_of_int indices)); ignore (call ~log:true (["addr"; "add"; addr; "dev"; dev] @ broadcast)) with _ -> () + let set_ipv6_link_local_addr dev = + let addr = get_ipv6_link_local_addr dev in + try + ignore (call ~log:true ["addr"; "add"; addr; "dev"; dev; "scope"; "link"]) + with _ -> () + let flush_ip_addr ?(ipv6=false) dev = try - if ipv6 then begin - ignore (call ~log:true ["-6"; "addr"; "flush"; "dev"; dev; "scope"; "global"]); - ignore (call ~log:true ["-6"; "addr"; "flush"; "dev"; dev; "scope"; "site"]) - end else - ignore (call ~log:true ["-4"; "addr"; "flush"; "dev"; dev]) + let mode = if ipv6 then "-6" else "-4" in + ignore (call ~log:true [mode; "addr"; "flush"; "dev"; dev]) with _ -> () let route_show ?(version=V46) dev = diff --git a/networkd/network_server.ml b/networkd/network_server.ml index c5b3f0bb8..258d8aaa3 100644 --- a/networkd/network_server.ml +++ b/networkd/network_server.ml @@ -194,20 +194,30 @@ module Interface = struct Sysctl.set_ipv6_autoconf name false; Ip.flush_ip_addr ~ipv6:true name end + | Linklocal6 -> + if List.mem name (Sysfs.list ()) then begin + Dhcp6c.stop name; + Sysctl.set_ipv6_autoconf name false; + Ip.flush_ip_addr ~ipv6:true name; + Ip.set_ipv6_link_local_addr name + end | DHCP6 -> Dhcp6c.stop name; Sysctl.set_ipv6_autoconf name false; Ip.flush_ip_addr ~ipv6:true name; + Ip.set_ipv6_link_local_addr name; Dhcp6c.start name | Autoconf6 -> Dhcp6c.stop name; Ip.flush_ip_addr ~ipv6:true name; + Ip.set_ipv6_link_local_addr name; Sysctl.set_ipv6_autoconf name true; (* Cannot link set down/up due to CA-89882 - IPv4 default route cleared *) | Static6 addrs -> Dhcp6c.stop name; Sysctl.set_ipv6_autoconf name false; Ip.flush_ip_addr ~ipv6:true name; + Ip.set_ipv6_link_local_addr name; List.iter (Ip.set_ip_addr name) addrs ) () diff --git a/networkd_db/networkd_db.ml b/networkd_db/networkd_db.ml index 9425ca151..f96fcb76d 100644 --- a/networkd_db/networkd_db.ml +++ b/networkd_db/networkd_db.ml @@ -88,7 +88,7 @@ let _ = | Some addr -> ["gatewayv6", Unix.string_of_inet_addr addr] in mode @ addrs @ gateway - | None6 -> [] + | None6 | Linklocal6 -> [] in let data = datav4 @ datav6 in List.iter (fun (k, v) -> Printf.printf "%s=%s\n" k v) data