1111#include "ether-addr-util.h"
1212#include "lockfile-util.h"
1313#include "missing_network.h"
14+ #include "netif-naming-scheme.h"
1415#include "netlink-util.h"
1516#include "nspawn-network.h"
1617#include "parse-util.h"
2728#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
2829#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
2930#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
31+ #define SHORTEN_IFNAME_HASH_KEY SD_ID128_MAKE(e1,90,a4,04,a8,ef,4b,51,8c,cc,c3,3a,9f,11,fc,a2)
3032
3133static int remove_one_link (sd_netlink * rtnl , const char * name ) {
3234 _cleanup_ (sd_netlink_message_unrefp ) sd_netlink_message * m = NULL ;
@@ -169,23 +171,67 @@ static int add_veth(
169171 return 0 ;
170172}
171173
174+ /* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet, since we
175+ * don't want "/" appear in interface names (since interfaces appear in sysfs as filenames). See section #5
176+ * of RFC 4648. */
177+ static char urlsafe_base64char (int x ) {
178+ static const char table [64 ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
179+ "abcdefghijklmnopqrstuvwxyz"
180+ "0123456789-_" ;
181+ return table [x & 63 ];
182+ }
183+
184+ static void shorten_ifname (char * ifname ) {
185+ char new_ifname [IFNAMSIZ ];
186+
187+ assert (ifname );
188+
189+ if (strlen (ifname ) < IFNAMSIZ ) /* Name is short enough */
190+ return ;
191+
192+ if (naming_scheme_has (NAMING_NSPAWN_LONG_HASH )) {
193+ uint64_t h ;
194+
195+ /* Calculate 64bit hash value */
196+ h = siphash24 (ifname , strlen (ifname ), SHORTEN_IFNAME_HASH_KEY .bytes );
197+
198+ /* Set the final four bytes (i.e. 32bit) to the lower 24bit of the hash, encoded in url-safe base64 */
199+ memcpy (new_ifname , ifname , IFNAMSIZ - 5 );
200+ new_ifname [IFNAMSIZ - 5 ] = urlsafe_base64char (h >> 18 );
201+ new_ifname [IFNAMSIZ - 4 ] = urlsafe_base64char (h >> 12 );
202+ new_ifname [IFNAMSIZ - 3 ] = urlsafe_base64char (h >> 6 );
203+ new_ifname [IFNAMSIZ - 2 ] = urlsafe_base64char (h );
204+ } else
205+ /* On old nspawn versions we just truncated the name, provide compatibility */
206+ memcpy (new_ifname , ifname , IFNAMSIZ - 1 );
207+
208+ new_ifname [IFNAMSIZ - 1 ] = 0 ;
209+
210+ /* Log the incident to make it more discoverable */
211+ log_warning ("Network interface name '%s' has been changed to '%s' to fit length constraints." , ifname , new_ifname );
212+
213+ strcpy (ifname , new_ifname );
214+ }
215+
172216int setup_veth (const char * machine_name ,
173217 pid_t pid ,
174218 char iface_name [IFNAMSIZ ],
175219 bool bridge ) {
176220
177221 _cleanup_ (sd_netlink_unrefp ) sd_netlink * rtnl = NULL ;
178222 struct ether_addr mac_host , mac_container ;
179- int r , i ;
223+ unsigned u ;
224+ char * n ;
225+ int r ;
180226
181227 assert (machine_name );
182228 assert (pid > 0 );
183229 assert (iface_name );
184230
185231 /* Use two different interface name prefixes depending whether
186232 * we are in bridge mode or not. */
187- snprintf ( iface_name , IFNAMSIZ - 1 , "%s-%s" ,
188- bridge ? "vb" : "ve" , machine_name );
233+ n = strjoina ( bridge ? "vb-" : "ve-" , machine_name );
234+ shorten_ifname ( n );
189235
190236 r = generate_mac (machine_name , & mac_container , CONTAINER_HASH_KEY , 0 );
191237 if (r < 0 )
@@ -199,15 +245,16 @@ int setup_veth(const char *machine_name,
199245 if (r < 0 )
200246 return log_error_errno (r , "Failed to connect to netlink: %m" );
201247
202- r = add_veth (rtnl , pid , iface_name , & mac_host , "host0" , & mac_container );
248+ r = add_veth (rtnl , pid , n , & mac_host , "host0" , & mac_container );
203249 if (r < 0 )
204250 return r ;
205251
206- r = parse_ifindex_or_ifname ( iface_name , & i );
207- if (r < 0 )
208- return log_error_errno (r , "Failed to resolve interface %s: %m" , iface_name );
252+ u = if_nametoindex ( n );
253+ if (u == 0 )
254+ return log_error_errno (errno , "Failed to resolve interface %s: %m" , n );
209255
210- return i ;
256+ strcpy (iface_name , n );
257+ return (int ) u ;
211258}
212259
213260int setup_veth_extra (
@@ -503,7 +550,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
503550 if (!n )
504551 return log_oom ();
505552
506- strshorten ( n , IFNAMSIZ - 1 );
553+ shorten_ifname ( n );
507554
508555 r = sd_netlink_message_append_string (m , IFLA_IFNAME , n );
509556 if (r < 0 )
@@ -578,7 +625,7 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
578625 if (!n )
579626 return log_oom ();
580627
581- strshorten ( n , IFNAMSIZ - 1 );
628+ shorten_ifname ( n );
582629
583630 r = sd_netlink_message_append_string (m , IFLA_IFNAME , n );
584631 if (r < 0 )
0 commit comments