diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-12-01 17:45:27 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-12-01 17:45:27 +0100 |
commit | 193bf9291831729f0f75e018104423ffa4e5f8aa (patch) | |
tree | c8c75adce9b2f6d451253537fd25cd3a570540ea | |
parent | 604711488d92962868fbf960c7d201f6b6842a2f (diff) | |
parent | 818f7f57243feb31ac9089d1f787e70ff9dc63a6 (diff) | |
download | NetworkManager-193bf9291831729f0f75e018104423ffa4e5f8aa.tar.gz |
merge: branch 'bg/device-creation-ip-tunnel-bgo758047'
Add support for creating IP tunnel interfaces.
https://bugzilla.gnome.org/show_bug.cgi?id=758047
42 files changed, 4119 insertions, 385 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c index bb07552f9c..659815a2f6 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -116,6 +116,7 @@ extern NmcOutputField nmc_fields_setting_team[]; extern NmcOutputField nmc_fields_setting_team_port[]; extern NmcOutputField nmc_fields_setting_dcb[]; extern NmcOutputField nmc_fields_setting_tun[]; +extern NmcOutputField nmc_fields_setting_ip_tunnel[]; /* Available settings for 'connection show <con>' - profile part */ static NmcOutputField nmc_fields_settings_names[] = { @@ -145,6 +146,7 @@ static NmcOutputField nmc_fields_settings_names[] = { SETTING_FIELD (NM_SETTING_TEAM_PORT_SETTING_NAME, nmc_fields_setting_team_port + 1), /* 23 */ SETTING_FIELD (NM_SETTING_DCB_SETTING_NAME, nmc_fields_setting_dcb + 1), /* 24 */ SETTING_FIELD (NM_SETTING_TUN_SETTING_NAME, nmc_fields_setting_tun + 1), /* 25 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_SETTING_NAME, nmc_fields_setting_ip_tunnel + 1), /* 26 */ {NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0} }; #define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\ @@ -171,7 +173,8 @@ static NmcOutputField nmc_fields_settings_names[] = { NM_SETTING_TEAM_SETTING_NAME","\ NM_SETTING_TEAM_PORT_SETTING_NAME"," \ NM_SETTING_DCB_SETTING_NAME"," \ - NM_SETTING_TUN_SETTING_NAME + NM_SETTING_TUN_SETTING_NAME"," \ + NM_SETTING_IP_TUNNEL_SETTING_NAME #define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X /* Active connection data */ @@ -2757,6 +2760,14 @@ static const NameItem nmc_tun_settings [] = { { NULL, NULL, NULL, FALSE } }; +static const NameItem nmc_ip_tunnel_settings [] = { + { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, + { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, NULL, TRUE }, + { NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, + { NULL, NULL, NULL, FALSE } +}; + /* Available connection types */ static const NameItem nmc_valid_connection_types[] = { { NM_SETTING_GENERIC_SETTING_NAME, NULL, nmc_generic_settings }, @@ -2779,6 +2790,7 @@ static const NameItem nmc_valid_connection_types[] = { { "team-slave", NULL, nmc_team_slave_settings }, { "bridge-slave", NULL, nmc_bridge_slave_settings }, { NM_SETTING_TUN_SETTING_NAME, NULL, nmc_tun_settings }, + { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, nmc_ip_tunnel_settings }, { NULL, NULL, NULL } }; @@ -4383,6 +4395,31 @@ do_questionnaire_tun (char **user, char **group, } } +static void +do_questionnaire_ip_tunnel (char **local) +{ + gboolean once_more; + + /* Ask for optional 'ip-tunnel' arguments. */ + if (!want_provide_opt_args (_("IP Tunnel"), 1)) + return; + + if (!*local) { + do { + *local = nmc_readline (_("Local endpoint [none]: ")); + if (!*local) + break; + once_more = !nm_utils_ipaddr_valid (AF_INET, *local) + && !nm_utils_ipaddr_valid (AF_INET6, *local); + if (once_more) { + g_print (_("Error: 'local': '%s' is not valid; must be an IP address\n"), + *local); + g_free (*local); + } + } while (once_more); + } +} + static gboolean read_connection_properties (NMConnection *connection, int argc, @@ -4594,6 +4631,7 @@ complete_connection_by_type (NMConnection *connection, NMSettingOlpcMesh *s_olpc_mesh; NMSettingAdsl *s_adsl; NMSettingTun *s_tun; + NMSettingIPTunnel *s_ip_tunnel; const char *slave_type; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -5813,6 +5851,96 @@ cleanup_tun: g_free (multi_queue); if (!success) return FALSE; + + } else if (!strcmp (con_type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) { + /* Build up the settings required for 'ip-tunnel' */ + const char *mode_c = NULL, *local_c = NULL, *remote_c = NULL; + char *mode_ask = NULL, *remote_ask = NULL, *local = NULL; + gboolean success = FALSE; + NMIPTunnelMode mode_enum; + nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !ask}, + {"local", TRUE, &local_c, FALSE}, + {"remote", TRUE, &remote_c, !ask}, + {NULL} }; + + if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error)) + return FALSE; + + if (!mode_c && ask) + mode_c = mode_ask = nmc_readline (_("Tunnel mode: ")); + if (!mode_c) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'mode' is required.")); + goto cleanup_tunnel; + } + + if (!remote_c && ask) + remote_c = remote_ask = nmc_readline (_("Remote endpoint: ")); + if (!remote_c) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'remote' is required.")); + goto cleanup_tunnel; + } + + if (!nm_utils_enum_from_str (nm_ip_tunnel_mode_get_type (), + mode_c, (int *) &mode_enum, NULL)) { + gs_free const char **values = NULL; + gs_free char *values_str = NULL; + + values = nm_utils_enum_get_values (nm_ip_tunnel_mode_get_type (), + NM_IP_TUNNEL_MODE_UKNOWN + 1, + G_MAXINT); + values_str = g_strjoinv (",", (char **) values); + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'mode': '%s' is not valid, use one of %s"), + mode_c, values_str); + goto cleanup_tunnel; + } + + if ( !nm_utils_ipaddr_valid (AF_INET, remote_c) + && !nm_utils_ipaddr_valid (AF_INET6, remote_c)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'remote': '%s' is not valid; must be an IP address"), + remote_c); + goto cleanup_tunnel; + } + + local = g_strdup (local_c); + if (ask) + do_questionnaire_ip_tunnel (&local); + + if ( local + && !nm_utils_ipaddr_valid (AF_INET, local) + && !nm_utils_ipaddr_valid (AF_INET6, local)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'local': '%s' is not valid; must be an IP address"), + local); + goto cleanup_tunnel; + } + + /* Add 'tunnel' setting */ + s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip_tunnel)); + + /* Set 'tunnel' properties */ + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_MODE, mode_enum, NULL); + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_REMOTE, remote_c, NULL); + if (local) + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_LOCAL, local, NULL); + + /* Set default values for IPv6 tunnels */ + if (nm_utils_ipaddr_valid (AF_INET6, remote_c)) { + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_TOS, 64, NULL); + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, 4, NULL); + } + + success = TRUE; +cleanup_tunnel: + g_free (remote_ask); + g_free (mode_ask); + if (!success) + return FALSE; + } else if (!strcmp (con_type, NM_SETTING_GENERIC_SETTING_NAME)) { /* Add 'generic' setting */ s_generic = (NMSettingGeneric *) nm_setting_generic_new (); diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion index 1827551b0c..2424fc6d7c 100644 --- a/clients/cli/nmcli-completion +++ b/clients/cli/nmcli-completion @@ -401,7 +401,7 @@ _nmcli_compl_ARGS() # user friendly. Only complete them, if the current word already starts with an "8". _nmcli_list "802-3-ethernet 802-11-wireless 802-11-olpc-mesh" else - _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun" + _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun ip-tunnel" fi return 0 fi diff --git a/clients/cli/settings.c b/clients/cli/settings.c index bf2cadc707..3e8c10f4c2 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -718,6 +718,36 @@ NmcOutputField nmc_fields_setting_tun[] = { NM_SETTING_TUN_MULTI_QUEUE #define NMC_FIELDS_SETTING_TUN_COMMON NMC_FIELDS_SETTING_TUN_ALL +/* Available fields for NM_SETTING_IP_TUNNEL_SETTING_NAME */ +NmcOutputField nmc_fields_setting_ip_tunnel[] = { + SETTING_FIELD ("name"), /* 0 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_MODE), /* 1 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_PARENT), /* 2 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_LOCAL), /* 3 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_REMOTE), /* 4 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_TTL), /* 5 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_TOS), /* 6 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY), /* 7 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_INPUT_KEY), /* 8 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_OUTPUT_KEY), /* 9 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT), /* 10 */ + SETTING_FIELD (NM_SETTING_IP_TUNNEL_FLOW_LABEL), /* 11 */ + {NULL, NULL, 0, NULL, FALSE, FALSE, 0} +}; +#define NMC_FIELDS_SETTING_IP_TUNNEL_ALL "name"","\ + NM_SETTING_IP_TUNNEL_MODE","\ + NM_SETTING_IP_TUNNEL_PARENT","\ + NM_SETTING_IP_TUNNEL_LOCAL","\ + NM_SETTING_IP_TUNNEL_REMOTE","\ + NM_SETTING_IP_TUNNEL_TTL","\ + NM_SETTING_IP_TUNNEL_TOS","\ + NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY","\ + NM_SETTING_IP_TUNNEL_INPUT_KEY","\ + NM_SETTING_IP_TUNNEL_OUTPUT_KEY","\ + NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT","\ + NM_SETTING_IP_TUNNEL_FLOW_LABEL +#define NMC_FIELDS_SETTING_IP_TUNNEL_COMMON NMC_FIELDS_SETTING_IP_TUNNEL_ALL + /*----------------------------------------------------------------------------*/ static char * wep_key_type_to_string (NMWepKeyType type) @@ -1310,6 +1340,17 @@ DEFINE_GETTER (nmc_property_tun_get_pi, NM_SETTING_TUN_PI); DEFINE_GETTER (nmc_property_tun_get_vnet_hdr, NM_SETTING_TUN_VNET_HDR); DEFINE_GETTER (nmc_property_tun_get_multi_queue, NM_SETTING_TUN_MULTI_QUEUE); +DEFINE_GETTER (nmc_property_ip_tunnel_get_parent, NM_SETTING_IP_TUNNEL_PARENT); +DEFINE_GETTER (nmc_property_ip_tunnel_get_local, NM_SETTING_IP_TUNNEL_LOCAL); +DEFINE_GETTER (nmc_property_ip_tunnel_get_remote, NM_SETTING_IP_TUNNEL_REMOTE); +DEFINE_GETTER (nmc_property_ip_tunnel_get_ttl, NM_SETTING_IP_TUNNEL_TTL); +DEFINE_GETTER (nmc_property_ip_tunnel_get_tos, NM_SETTING_IP_TUNNEL_TOS); +DEFINE_GETTER (nmc_property_ip_tunnel_get_path_mtu_discovery, NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY); +DEFINE_GETTER (nmc_property_ip_tunnel_get_input_key, NM_SETTING_IP_TUNNEL_INPUT_KEY); +DEFINE_GETTER (nmc_property_ip_tunnel_get_output_key, NM_SETTING_IP_TUNNEL_OUTPUT_KEY); +DEFINE_GETTER (nmc_property_ip_tunnel_get_encapsulation_limit, NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT); +DEFINE_GETTER (nmc_property_ip_tunnel_get_flow_label, NM_SETTING_IP_TUNNEL_FLOW_LABEL); + static char * nmc_property_ib_get_mtu (NMSetting *setting, NmcPropertyGetType get_type) { @@ -1665,6 +1706,44 @@ nmc_property_wired_set_wake_on_lan (NMSetting *setting, const char *prop, return TRUE; } +static char * +nmc_property_ip_tunnel_get_mode (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingIPTunnel *s_ip_tunnel = NM_SETTING_IP_TUNNEL (setting); + NMIPTunnelMode mode; + + mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); + return nm_utils_enum_to_str (nm_ip_tunnel_mode_get_type (), mode); +} + +static gboolean +nmc_property_ip_tunnel_set_mode (NMSetting *setting, const char *prop, + const char *val, GError **error) +{ + NMIPTunnelMode mode; + gboolean ret; + + ret = nm_utils_enum_from_str (nm_ip_tunnel_mode_get_type(), val, + (int *) &mode, NULL); + + if (!ret) { + gs_free const char **values = NULL; + gs_free char *values_str = NULL; + + values = nm_utils_enum_get_values (nm_ip_tunnel_mode_get_type (), + NM_IP_TUNNEL_MODE_UKNOWN + 1, + G_MAXINT); + values_str = g_strjoinv (",", (char **) values); + g_set_error (error, 1, 0, _("invalid mode '%s', use one of %s"), + val, values_str); + + return FALSE; + } + + g_object_set (setting, prop, mode, NULL); + return TRUE; +} + /* --- NM_SETTING_WIRELESS_SETTING_NAME property get functions --- */ DEFINE_GETTER (nmc_property_wireless_get_mode, NM_SETTING_WIRELESS_MODE) DEFINE_GETTER (nmc_property_wireless_get_band, NM_SETTING_WIRELESS_BAND) @@ -7073,6 +7152,85 @@ nmc_properties_init (void) NULL, NULL, NULL); + + /* Add editable properties for NM_SETTING_IP_TUNNEL_SETTING_NAME */ + nmc_add_prop_funcs (GLUE (IP_TUNNEL, MODE), + nmc_property_ip_tunnel_get_mode, + nmc_property_ip_tunnel_set_mode, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, PARENT), + nmc_property_ip_tunnel_get_parent, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, LOCAL), + nmc_property_ip_tunnel_get_local, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, REMOTE), + nmc_property_ip_tunnel_get_remote, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, TTL), + nmc_property_ip_tunnel_get_ttl, + nmc_property_set_uint, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, TOS), + nmc_property_ip_tunnel_get_tos, + nmc_property_set_uint, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, PATH_MTU_DISCOVERY), + nmc_property_ip_tunnel_get_path_mtu_discovery, + nmc_property_set_bool, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, INPUT_KEY), + nmc_property_ip_tunnel_get_input_key, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, OUTPUT_KEY), + nmc_property_ip_tunnel_get_output_key, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, ENCAPSULATION_LIMIT), + nmc_property_ip_tunnel_get_encapsulation_limit, + nmc_property_set_uint, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (IP_TUNNEL, FLOW_LABEL), + nmc_property_ip_tunnel_get_flow_label, + nmc_property_set_uint, + NULL, + NULL, + NULL, + NULL); } void @@ -8253,6 +8411,42 @@ setting_tun_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboo return TRUE; } +static gboolean +setting_ip_tunnel_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets) +{ + NMSettingIPTunnel *s_ip_tunnel = NM_SETTING_IP_TUNNEL (setting); + NmcOutputField *tmpl, *arr; + size_t tmpl_len; + + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (s_ip_tunnel), FALSE); + + tmpl = nmc_fields_setting_ip_tunnel; + tmpl_len = sizeof (nmc_fields_setting_ip_tunnel); + nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_IP_TUNNEL_ALL, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (nmc->output_data, arr); + + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); + set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting))); + set_val_str (arr, 1, nmc_property_ip_tunnel_get_mode (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 2, nmc_property_ip_tunnel_get_parent (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 3, nmc_property_ip_tunnel_get_local (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 4, nmc_property_ip_tunnel_get_remote (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 5, nmc_property_ip_tunnel_get_ttl (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 6, nmc_property_ip_tunnel_get_tos (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 7, nmc_property_ip_tunnel_get_path_mtu_discovery (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 8, nmc_property_ip_tunnel_get_input_key (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 9, nmc_property_ip_tunnel_get_output_key (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 10, nmc_property_ip_tunnel_get_encapsulation_limit (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 11, nmc_property_ip_tunnel_get_flow_label (setting, NMC_PROPERTY_GET_PRETTY)); + g_ptr_array_add (nmc->output_data, arr); + + print_data (nmc); /* Print all data */ + + return TRUE; +} + typedef struct { const char *sname; gboolean (*func) (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets); @@ -8285,6 +8479,7 @@ static const SettingDetails detail_printers[] = { { NM_SETTING_TEAM_PORT_SETTING_NAME, setting_team_port_details }, { NM_SETTING_DCB_SETTING_NAME, setting_dcb_details }, { NM_SETTING_TUN_SETTING_NAME, setting_tun_details }, + { NM_SETTING_IP_TUNNEL_SETTING_NAME, setting_ip_tunnel_details }, { NULL }, }; diff --git a/introspection/Makefile.am b/introspection/Makefile.am index c8a70cffc7..735921d373 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -31,10 +31,10 @@ nodist_libnmdbus_la_SOURCES = \ nmdbus-device.h \ nmdbus-device-generic.c \ nmdbus-device-generic.h \ - nmdbus-device-gre.c \ - nmdbus-device-gre.h \ nmdbus-device-infiniband.c \ nmdbus-device-infiniband.h \ + nmdbus-device-ip-tunnel.c \ + nmdbus-device-ip-tunnel.h \ nmdbus-device-macvlan.c \ nmdbus-device-macvlan.h \ nmdbus-device-modem.c \ @@ -108,8 +108,8 @@ EXTRA_DIST = \ nm-device-bt.xml \ nm-device-ethernet.xml \ nm-device-generic.xml \ - nm-device-gre.xml \ nm-device-infiniband.xml \ + nm-device-ip-tunnel.xml \ nm-device-macvlan.xml \ nm-device-modem.xml \ nm-device-olpc-mesh.xml \ diff --git a/introspection/nm-device-gre.xml b/introspection/nm-device-ip-tunnel.xml index ae418aab55..fcb42ce275 100644 --- a/introspection/nm-device-gre.xml +++ b/introspection/nm-device-ip-tunnel.xml @@ -1,7 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <interface name="org.freedesktop.NetworkManager.Device.Gre"> + <interface name="org.freedesktop.NetworkManager.Device.IPTunnel"> + + <property name="Mode" type="u" access="read"> + <tp:docstring> + The tunneling mode. + </tp:docstring> + </property> <property name="Parent" type="o" access="read"> <tp:docstring> @@ -9,63 +15,62 @@ </tp:docstring> </property> - <property name="InputFlags" type="q" access="read"> + <property name="Local" type="s" access="read"> <tp:docstring> - The expected set of GRE flags for incoming packets. (The - values are specified by the GRE specification. On Linux, they - are defined in <linux/if_tunnel.h>. Eg, GRE_KEY for the - 'Key Present' bit.) + The local endpoint of the tunnel. </tp:docstring> </property> - <property name="OutputFlags" type="q" access="read"> + <property name="Remote" type="s" access="read"> <tp:docstring> - The set of GRE flags to use for outgoing packets. (The - values are specified by the GRE specification. On Linux, they - are defined in <linux/if_tunnel.h>. Eg, GRE_KEY for the - 'Key Present' bit.) + The remote endpoint of the tunnel. </tp:docstring> </property> - <property name="InputKey" type="u" access="read"> + <property name="Ttl" type="y" access="read"> <tp:docstring> - Expected input key (if the "Key Present" bit is set in the input flags). + The TTL assigned to tunneled packets. 0 is a special value + meaning that packets inherit the TTL value </tp:docstring> </property> - <property name="OutputKey" type="u" access="read"> + <property name="Tos" type="y" access="read"> <tp:docstring> - Output key (if the "Key Present" bit is set in the output flags). + The type of service (IPv4) or traffic class (IPv6) assigned to + tunneled packets. </tp:docstring> </property> - <property name="Local" type="s" access="read"> + <property name="PathMtuDiscovery" type="b" access="read"> <tp:docstring> - The local end of the tunnel. + Whether path MTU discovery is enabled on this tunnel. </tp:docstring> </property> - <property name="Remote" type="s" access="read"> + <property name="InputKey" type="s" access="read"> <tp:docstring> - The remote end of the tunnel. + The key used for incoming packets. </tp:docstring> </property> - <property name="Ttl" type="y" access="read"> + <property name="OutputKey" type="s" access="read"> <tp:docstring> - The value to use in the IP TTL field for tunnel packets. + The key used for outgoing packets. </tp:docstring> </property> - <property name="Tos" type="y" access="read"> + <property name="EncapsulationLimit" type="y" access="read"> <tp:docstring> - The value to use in the IP ToS field for tunnel packets. + How many additional levels of encapsulation are permitted to + be prepended to packets. This property applies only to IPv6 + tunnels. </tp:docstring> </property> - <property name="PathMtuDiscovery" type="b" access="read"> + <property name="FlowLabel" type="u" access="read"> <tp:docstring> - Whether path MTU discovery is performed. + The flow label to assign to tunnel packets. This property + applies only to IPv6 tunnels. </tp:docstring> </property> diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core index 867dd9045d..02c1d1021b 100644 --- a/libnm-core/Makefile.libnm-core +++ b/libnm-core/Makefile.libnm-core @@ -25,6 +25,7 @@ libnm_core_headers = \ $(core)/nm-setting-gsm.h \ $(core)/nm-setting-infiniband.h \ $(core)/nm-setting-ip-config.h \ + $(core)/nm-setting-ip-tunnel.h \ $(core)/nm-setting-ip4-config.h \ $(core)/nm-setting-ip6-config.h \ $(core)/nm-setting-olpc-mesh.h \ @@ -82,6 +83,7 @@ libnm_core_sources = \ $(core)/nm-setting-gsm.c \ $(core)/nm-setting-infiniband.c \ $(core)/nm-setting-ip-config.c \ + $(core)/nm-setting-ip-tunnel.c \ $(core)/nm-setting-ip4-config.c \ $(core)/nm-setting-ip6-config.c \ $(core)/nm-setting-olpc-mesh.c \ diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 94a897539a..e801f2fd47 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1595,7 +1595,8 @@ nm_connection_is_virtual (NMConnection *connection) || !strcmp (type, NM_SETTING_TEAM_SETTING_NAME) || !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME) - || !strcmp (type, NM_SETTING_TUN_SETTING_NAME)) + || !strcmp (type, NM_SETTING_TUN_SETTING_NAME) + || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) return TRUE; if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { @@ -1866,6 +1867,24 @@ nm_connection_get_setting_ip4_config (NMConnection *connection) } /** + * nm_connection_get_setting_ip_tunnel: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingIPTunnel the connection might contain. + * + * Returns: (transfer none): an #NMSettingIPTunnel if the connection contains one, otherwise %NULL + * + * Since: 1.2 + **/ +NMSettingIPTunnel * +nm_connection_get_setting_ip_tunnel (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingIPTunnel *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP_TUNNEL); +} + +/** * nm_connection_get_setting_ip6_config: * @connection: the #NMConnection * diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index fc2117f61e..8896e59bab 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -202,6 +202,8 @@ NMSettingDcb * nm_connection_get_setting_dcb (NMConnec NMSettingGeneric * nm_connection_get_setting_generic (NMConnection *connection); NMSettingGsm * nm_connection_get_setting_gsm (NMConnection *connection); NMSettingInfiniband * nm_connection_get_setting_infiniband (NMConnection *connection); +NM_AVAILABLE_IN_1_2 +NMSettingIPTunnel * nm_connection_get_setting_ip_tunnel (NMConnection *connection); NMSettingIPConfig * nm_connection_get_setting_ip4_config (NMConnection *connection); NMSettingIPConfig * nm_connection_get_setting_ip6_config (NMConnection *connection); NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index d1b0992900..c1eea777f2 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -49,6 +49,7 @@ #include "nm-setting-generic.h" #include "nm-setting-gsm.h" #include "nm-setting-infiniband.h" +#include "nm-setting-ip-tunnel.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-setting-olpc-mesh.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 1355c92da6..29a34cc68d 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -42,6 +42,7 @@ typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; typedef struct _NMSettingInfiniband NMSettingInfiniband; typedef struct _NMSettingIPConfig NMSettingIPConfig; +typedef struct _NMSettingIPTunnel NMSettingIPTunnel; typedef struct _NMSettingIP4Config NMSettingIP4Config; typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index ddd6834c23..f901028f9b 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -67,7 +67,7 @@ #define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan" #define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" - +#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel" #define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings" #define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings" @@ -173,6 +173,7 @@ typedef enum { NM_DEVICE_TYPE_GENERIC = 14, NM_DEVICE_TYPE_TEAM = 15, NM_DEVICE_TYPE_TUN = 16, + NM_DEVICE_TYPE_IP_TUNNEL = 17, } NMDeviceType; /** @@ -668,4 +669,34 @@ typedef enum /*< flags >*/ { #define NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE "nearest-non-tpmr-bridge" #define NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE "nearest-customer-bridge" +/** + * NMIPTunnelMode: + * @NM_IP_TUNNEL_MODE_UNKNOWN: Unknown/unset tunnel mode + * @NM_IP_TUNNEL_MODE_IPIP: IP in IP tunnel + * @NM_IP_TUNNEL_MODE_GRE: GRE tunnel + * @NM_IP_TUNNEL_MODE_SIT: SIT tunnel + * @NM_IP_TUNNEL_MODE_ISATAP: ISATAP tunnel + * @NM_IP_TUNNEL_MODE_VTI: VTI tunnel + * @NM_IP_TUNNEL_MODE_IP6IP6: IPv6 in IPv6 tunnel + * @NM_IP_TUNNEL_MODE_IPIP6: IPv4 in IPv6 tunnel + * @NM_IP_TUNNEL_MODE_IP6GRE: IPv6 GRE tunnel + * @NM_IP_TUNNEL_MODE_VTI6: IPv6 VTI tunnel + * + * The tunneling mode. + * + * Since: 1.2 + */ +typedef enum { + NM_IP_TUNNEL_MODE_UKNOWN = 0, + NM_IP_TUNNEL_MODE_IPIP = 1, + NM_IP_TUNNEL_MODE_GRE = 2, + NM_IP_TUNNEL_MODE_SIT = 3, + NM_IP_TUNNEL_MODE_ISATAP = 4, + NM_IP_TUNNEL_MODE_VTI = 5, + NM_IP_TUNNEL_MODE_IP6IP6 = 6, + NM_IP_TUNNEL_MODE_IPIP6 = 7, + NM_IP_TUNNEL_MODE_IP6GRE = 8, + NM_IP_TUNNEL_MODE_VTI6 = 9, +} NMIPTunnelMode; + #endif /* __NM_DBUS_INTERFACE_H__ */ diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c new file mode 100644 index 0000000000..d561524950 --- /dev/null +++ b/libnm-core/nm-setting-ip-tunnel.c @@ -0,0 +1,724 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#include "nm-setting-ip-tunnel.h" + +#include "config.h" + +#include "nm-setting-private.h" +#include "nm-macros-internal.h" +#include "nm-utils.h" + +/** + * SECTION:nm-setting-tunnel + * @short_description: Describes connection properties for IP tunnel devices + **/ + +G_DEFINE_TYPE_WITH_CODE (NMSettingIPTunnel, nm_setting_ip_tunnel, NM_TYPE_SETTING, + _nm_register_setting (IP_TUNNEL, 1)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_IP_TUNNEL) + +#define NM_SETTING_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelPrivate)) + +typedef struct { + char *parent; + NMIPTunnelMode mode; + char *local; + char *remote; + guint ttl; + guint tos; + gboolean path_mtu_discovery; + char *input_key; + char *output_key; + guint encapsulation_limit; + guint flow_label; +} NMSettingIPTunnelPrivate; + +enum { + PROP_0, + PROP_PARENT, + PROP_MODE, + PROP_LOCAL, + PROP_REMOTE, + PROP_TTL, + PROP_TOS, + PROP_PATH_MTU_DISCOVERY, + PROP_INPUT_KEY, + PROP_OUTPUT_KEY, + PROP_ENCAPSULATION_LIMIT, + PROP_FLOW_LABEL, + + LAST_PROP +}; + +/** + * nm_setting_ip_tunnel_get_parent: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:parent property of the setting + * + * Returns: the parent device + * + * Since: 1.2 + **/ +const char * +nm_setting_ip_tunnel_get_parent (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL); + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->parent; +} + +/** + * nm_setting_ip_tunnel_get_mode: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:mode property of the setting. + * + * Returns: the tunnel mode + * + * Since: 1.2 + **/ +NMIPTunnelMode +nm_setting_ip_tunnel_get_mode (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->mode; +} + +/** + * nm_setting_ip_tunnel_get_local: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:local property of the setting. + * + * Returns: the local endpoint + * + * Since: 1.2 + **/ +const char * +nm_setting_ip_tunnel_get_local (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->local; +} + +/** + * nm_setting_ip_tunnel_get_remote: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:remote property of the setting. + * + * Returns: the remote endpoint + * + * Since: 1.2 + **/ +const char * +nm_setting_ip_tunnel_get_remote (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->remote; +} + +/** + * nm_setting_ip_tunnel_get_ttl: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:ttl property of the setting. + * + * Returns: the Time-to-live value + * + * Since: 1.2 + **/ + +guint +nm_setting_ip_tunnel_get_ttl (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->ttl; +} + +/** + * nm_setting_ip_tunnel_get_tos: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:tos property of the setting. + * + * Returns: the TOS value + * + * Since: 1.2 + **/ +guint +nm_setting_ip_tunnel_get_tos (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->tos; +} + +/** + * nm_setting_ip_tunnel_get_path_mtu_discovery: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:path-mtu-discovery property of the setting. + * + * Returns: whether path MTU discovery is enabled + * + * Since: 1.2 + **/ +gboolean +nm_setting_ip_tunnel_get_path_mtu_discovery (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), TRUE); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->path_mtu_discovery; +} + +/** + * nm_setting_ip_tunnel_get_input_key: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:input-key property of the setting. + * + * Returns: the input key + * + * Since: 1.2 + **/ +const char * +nm_setting_ip_tunnel_get_input_key (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->input_key; +} + +/** + * nm_setting_ip_tunnel_get_output_key: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:output-key property of the setting. + * + * Returns: the output key + * + * Since: 1.2 + **/ +const char * +nm_setting_ip_tunnel_get_output_key (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->output_key; +} + +/** + * nm_setting_ip_tunnel_get_encapsulation_limit: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:encapsulation-limit property of the setting. + * + * Returns: the encapsulation limit value + * + * Since: 1.2 + **/ +guint +nm_setting_ip_tunnel_get_encapsulation_limit (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->encapsulation_limit; +} + +/** + * nm_setting_ip_tunnel_get_flow_label: + * @setting: the #NMSettingIPTunnel + * + * Returns the #NMSettingIPTunnel:flow-label property of the setting. + * + * Returns: the flow label value + * + * Since: 1.2 + **/ +guint +nm_setting_ip_tunnel_get_flow_label (NMSettingIPTunnel *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0); + + return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->flow_label; +} + +/*********************************************************************/ + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting); + int family; + + switch (priv->mode) { + case NM_IP_TUNNEL_MODE_IPIP: + case NM_IP_TUNNEL_MODE_SIT: + case NM_IP_TUNNEL_MODE_ISATAP: + case NM_IP_TUNNEL_MODE_GRE: + case NM_IP_TUNNEL_MODE_VTI: + family = AF_INET; + break; + case NM_IP_TUNNEL_MODE_IP6IP6: + case NM_IP_TUNNEL_MODE_IPIP6: + case NM_IP_TUNNEL_MODE_IP6GRE: + case NM_IP_TUNNEL_MODE_VTI6: + family = AF_INET6; + break; + default: + family = AF_UNSPEC; + } + + if (family == AF_UNSPEC) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%d' is not a valid tunnel mode"), + (int) priv->mode); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_MODE); + return FALSE; + } + + if ( priv->parent + && !nm_utils_iface_valid_name (priv->parent) + && !nm_utils_is_uuid (priv->parent)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is neither an UUID nor an interface name"), + priv->parent); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_IP_TUNNEL_PARENT); + return FALSE; + } + + if (priv->local && !nm_utils_ipaddr_valid (family, priv->local)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IPv%c address"), + priv->local, + family == AF_INET ? '4' : '6'); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_LOCAL); + return FALSE; + } + + if (priv->remote && !nm_utils_ipaddr_valid (family, priv->remote)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IPv%c address"), + priv->remote, + family == AF_INET ? '4' : '6'); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_REMOTE); + return FALSE; + } + + if ( (priv->input_key && priv->input_key[0]) + || (priv->output_key && priv->output_key[0])) { + if ( priv->mode != NM_IP_TUNNEL_MODE_GRE + && priv->mode != NM_IP_TUNNEL_MODE_IP6GRE) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("tunnel keys can only be specified for GRE tunnels")); + return FALSE; + } + } + + if (priv->input_key && priv->input_key[0]) { + gint64 val; + + val = _nm_utils_ascii_str_to_int64 (priv->input_key, 10, 0, G_MAXUINT32, -1); + if (val == -1) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid tunnel key"), + priv->input_key); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_IP_TUNNEL_INPUT_KEY); + return FALSE; + } + } + + if (priv->output_key && priv->output_key[0]) { + gint64 val; + + val = _nm_utils_ascii_str_to_int64 (priv->output_key, 10, 0, G_MAXUINT32, -1); + if (val == -1) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid tunnel key"), + priv->output_key); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_IP_TUNNEL_OUTPUT_KEY); + return FALSE; + } + } + + if (!priv->path_mtu_discovery && priv->ttl != 0) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("a fixed TTL is allowed only when path MTU discovery is enabled")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_IP_TUNNEL_TTL); + return FALSE; + } + + return TRUE; +} + +/** + * nm_setting_ip_tunnel_new: + * + * Creates a new #NMSettingIPTunnel object with default values. + * + * Returns: (transfer full): the new empty #NMSettingIPTunnel object + * + * Since: 1.2 + **/ +NMSetting * +nm_setting_ip_tunnel_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP_TUNNEL, NULL); +} + +static void +nm_setting_ip_tunnel_init (NMSettingIPTunnel *setting) +{ +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object); + NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting); + + switch (prop_id) { + case PROP_PARENT: + g_free (priv->parent); + priv->parent = g_value_dup_string (value); + break; + case PROP_MODE: + priv->mode = g_value_get_uint (value); + break; + case PROP_LOCAL: + g_free (priv->local); + priv->local = g_value_dup_string (value); + break; + case PROP_REMOTE: + g_free (priv->remote); + priv->remote = g_value_dup_string (value); + break; + case PROP_TTL: + priv->ttl = g_value_get_uint (value); + break; + case PROP_TOS: + priv->tos = g_value_get_uint (value); + break; + case PROP_PATH_MTU_DISCOVERY: + priv->path_mtu_discovery = g_value_get_boolean (value); + break; + case PROP_INPUT_KEY: + g_free (priv->input_key); + priv->input_key = g_value_dup_string (value); + break; + case PROP_OUTPUT_KEY: + g_free (priv->output_key); + priv->output_key = g_value_dup_string (value); + break; + case PROP_ENCAPSULATION_LIMIT: + priv->encapsulation_limit = g_value_get_uint (value); + break; + case PROP_FLOW_LABEL: + priv->flow_label = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object); + NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting); + + switch (prop_id) { + case PROP_PARENT: + g_value_set_string (value, priv->parent); + break; + case PROP_MODE: + g_value_set_uint (value, priv->mode); + break; + case PROP_LOCAL: + g_value_set_string (value, priv->local); + break; + case PROP_REMOTE: + g_value_set_string (value, priv->remote); + break; + case PROP_TTL: + g_value_set_uint (value, priv->ttl); + break; + case PROP_TOS: + g_value_set_uint (value, priv->tos); + break; + case PROP_PATH_MTU_DISCOVERY: + g_value_set_boolean (value, priv->path_mtu_discovery); + break; + case PROP_INPUT_KEY: + g_value_set_string (value, priv->input_key); + break; + case PROP_OUTPUT_KEY: + g_value_set_string (value, priv->output_key); + break; + case PROP_ENCAPSULATION_LIMIT: + g_value_set_uint (value, priv->encapsulation_limit); + break; + case PROP_FLOW_LABEL: + g_value_set_uint (value, priv->flow_label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +finalize (GObject *object) +{ + NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object); + NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting); + + g_free (priv->local); + g_free (priv->remote); + g_free (priv->input_key); + g_free (priv->output_key); + + G_OBJECT_CLASS (nm_setting_ip_tunnel_parent_class)->finalize (object); +} + +static void +nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + g_type_class_add_private (setting_class, sizeof (NMSettingIPTunnelPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingIPTunnel:parent: + * + * If given, specifies the parent interface name or parent connection UUID + * the new device will be bound to so that tunneled packets will only be + * routed via that interface. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_string (NM_SETTING_IP_TUNNEL_PARENT, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:mode: + * + * The tunneling mode, for example %NM_IP_TUNNEL_MODE_IPIP or + * %NM_IP_TUNNEL_MODE_GRE. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_MODE, + g_param_spec_uint (NM_SETTING_IP_TUNNEL_MODE, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:local: + * + * The local endpoint of the tunnel; the value can be empty, otherwise it + * must contain an IPv4 or IPv6 address. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_LOCAL, + g_param_spec_string (NM_SETTING_IP_TUNNEL_LOCAL, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:remote: + * + * The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 + * address. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_REMOTE, + g_param_spec_string (NM_SETTING_IP_TUNNEL_REMOTE, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:ttl + * + * The TTL to assign to tunneled packets. 0 is a special value meaning that + * packets inherit the TTL value. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_TTL, + g_param_spec_uint (NM_SETTING_IP_TUNNEL_TTL, "", "", + 0, 255, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:tos + * + * The type of service (IPv4) or traffic class (IPv6) field to be set on + * tunneled packets. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_TOS, + g_param_spec_uint (NM_SETTING_IP_TUNNEL_TOS, "", "", + 0, 255, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:path-mtu-discovery + * + * Whether to enable Path MTU Discovery on this tunnel. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_PATH_MTU_DISCOVERY, + g_param_spec_boolean (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:input-key: + * + * The key used for tunnel input packets; the property is valid only for + * certain tunnel modes (GRE, IP6GRE). If empty, no key is used. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_INPUT_KEY, + g_param_spec_string (NM_SETTING_IP_TUNNEL_INPUT_KEY, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:output-key: + * + * The key used for tunnel output packets; the property is valid only for + * certain tunnel modes (GRE, IP6GRE). If empty, no key is used. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_OUTPUT_KEY, + g_param_spec_string (NM_SETTING_IP_TUNNEL_OUTPUT_KEY, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:encapsulation-limit: + * + * How many additional levels of encapsulation are permitted to be prepended + * to packets. This property applies only to IPv6 tunnels. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_ENCAPSULATION_LIMIT, + g_param_spec_uint (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "", + 0, 255, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPTunnel:flow-label: + * + * The flow label to assign to tunnel packets. This property applies only to + * IPv6 tunnels. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_FLOW_LABEL, + g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLOW_LABEL, "", "", + 0, (1 << 20) - 1, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ip-tunnel.h b/libnm-core/nm-setting-ip-tunnel.h new file mode 100644 index 0000000000..a07bd50db0 --- /dev/null +++ b/libnm-core/nm-setting-ip-tunnel.h @@ -0,0 +1,95 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_IP_TUNNEL_H__ +#define __NM_SETTING_IP_TUNNEL_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include <nm-setting.h> + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_IP_TUNNEL (nm_setting_ip_tunnel_get_type ()) +#define NM_SETTING_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnel)) +#define NM_SETTING_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelClass)) +#define NM_IS_SETTING_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_IP_TUNNEL)) +#define NM_IS_SETTING_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_IP_TUNNEL)) +#define NM_SETTING_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelClass)) + +#define NM_SETTING_IP_TUNNEL_SETTING_NAME "ip-tunnel" + +#define NM_SETTING_IP_TUNNEL_PARENT "parent" +#define NM_SETTING_IP_TUNNEL_MODE "mode" +#define NM_SETTING_IP_TUNNEL_LOCAL "local" +#define NM_SETTING_IP_TUNNEL_REMOTE "remote" +#define NM_SETTING_IP_TUNNEL_TTL "ttl" +#define NM_SETTING_IP_TUNNEL_TOS "tos" +#define NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery" +#define NM_SETTING_IP_TUNNEL_INPUT_KEY "input-key" +#define NM_SETTING_IP_TUNNEL_OUTPUT_KEY "output-key" +#define NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" +#define NM_SETTING_IP_TUNNEL_FLOW_LABEL "flow-label" + +struct _NMSettingIPTunnel { + NMSetting parent; +}; + +typedef struct { + NMSettingClass parent; + + /*< private >*/ + gpointer padding[4]; +} NMSettingIPTunnelClass; + +NM_AVAILABLE_IN_1_2 +GType nm_setting_ip_tunnel_get_type (void); + +NM_AVAILABLE_IN_1_2 +NMSetting * nm_setting_ip_tunnel_new (void); + +NM_AVAILABLE_IN_1_2 +const char *nm_setting_ip_tunnel_get_parent (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +NMIPTunnelMode nm_setting_ip_tunnel_get_mode (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +const char *nm_setting_ip_tunnel_get_local (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +const char *nm_setting_ip_tunnel_get_remote (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +guint nm_setting_ip_tunnel_get_ttl (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +guint nm_setting_ip_tunnel_get_tos (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +gboolean nm_setting_ip_tunnel_get_path_mtu_discovery (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +const char *nm_setting_ip_tunnel_get_input_key (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +const char *nm_setting_ip_tunnel_get_output_key (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +guint nm_setting_ip_tunnel_get_encapsulation_limit (NMSettingIPTunnel *setting); +NM_AVAILABLE_IN_1_2 +guint nm_setting_ip_tunnel_get_flow_label (NMSettingIPTunnel *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_IP_TUNNEL_H__ */ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index e3c6b80bef..5e920de482 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4120,3 +4120,55 @@ NM_BACKPORT_SYMBOL (libnm_1_0_6, gboolean, nm_utils_enum_from_str, (GType type, const char *str, int *out_value, char **err_token), (type, str, out_value, err_token)); +/** + * nm_utils_enum_get_values: + * @type: the %GType of the enum + * @from: the first element to be returned + * @to: the last element to be returned + * + * Returns the list of possible values for a given enum. + * + * Returns: a NULL-terminated dynamically-allocated array of static strings + * or %NULL on error + * + * Since: 1.2 + */ +const char **nm_utils_enum_get_values (GType type, gint from, gint to) +{ + GTypeClass *class; + GPtrArray *array; + gint i; + + class = g_type_class_ref (type); + array = g_ptr_array_new (); + + if (G_IS_ENUM_CLASS (class)) { + GEnumClass *enum_class = G_ENUM_CLASS (class); + GEnumValue *enum_value; + + for (i = 0; i < enum_class->n_values; i++) { + enum_value = &enum_class->values[i]; + if (enum_value->value >= from && enum_value->value <= to) + g_ptr_array_add (array, (gpointer) enum_value->value_nick); + } + } else if (G_IS_FLAGS_CLASS (class)) { + GFlagsClass *flags_class = G_FLAGS_CLASS (class); + GFlagsValue *flags_value; + + for (i = 0; i < flags_class->n_values; i++) { + flags_value = &flags_class->values[i]; + if (flags_value->value >= from && flags_value->value <= to) + g_ptr_array_add (array, (gpointer) flags_value->value_nick); + } + } else { + g_type_class_unref (class); + g_ptr_array_free (array, TRUE); + g_return_val_if_reached (NULL); + } + + g_type_class_unref (class); + g_ptr_array_add (array, NULL); + + return (const char **) g_ptr_array_free (array, FALSE); +} + diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index 4be58e09a1..407c14e2c4 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -203,6 +203,9 @@ char *nm_utils_enum_to_str (GType type, int value); NM_AVAILABLE_IN_1_2 gboolean nm_utils_enum_from_str (GType type, const char *str, int *out_value, char **err_token); +NM_AVAILABLE_IN_1_2 +const char **nm_utils_enum_get_values (GType type, gint from, gint to); + G_END_DECLS #endif /* __NM_UTILS_H__ */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index f4dec283ce..e8eb0bafb5 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4740,6 +4740,21 @@ test_nm_utils_enum_to_str_do (GType type, int flags, const char *exp_str) g_free (str); } +static void +test_nm_utils_enum_get_values_do (GType type, int from, int to, const char *exp_str) +{ + const char **strv; + char *str; + + strv = nm_utils_enum_get_values (type, from, to); + g_assert (strv); + str = g_strjoinv (",", (char **) strv); + g_assert_cmpstr (str, ==, exp_str); + g_free (str); + g_free (strv); +} + + static void test_nm_utils_enum (void) { GType bool_enum = nm_test_general_bool_enum_get_type(); @@ -4783,6 +4798,12 @@ static void test_nm_utils_enum (void) test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE | NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL); test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white"); + + test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown"); + test_nm_utils_enum_get_values_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, + NM_TEST_GENERAL_BOOL_ENUM_MAYBE, "yes,maybe"); + test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz"); + test_nm_utils_enum_get_values_do (color_flags, 0, G_MAXINT, "blue,red,green"); } /******************************************************************************/ diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c index aac94fb1dc..ce76432107 100644 --- a/libnm-glib/nm-device.c +++ b/libnm-glib/nm-device.c @@ -321,6 +321,7 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype) return NM_TYPE_DEVICE_VLAN; case NM_DEVICE_TYPE_GENERIC: case NM_DEVICE_TYPE_TUN: + case NM_DEVICE_TYPE_IP_TUNNEL: return NM_TYPE_DEVICE_GENERIC; default: g_warning ("Unknown device type %d", dtype); diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h index 71862c42eb..8101082b77 100644 --- a/libnm-util/NetworkManager.h +++ b/libnm-util/NetworkManager.h @@ -152,6 +152,7 @@ typedef enum { * @NM_DEVICE_TYPE_BRIDGE: a bridge master interface * @NM_DEVICE_TYPE_TEAM: a team master interface * @NM_DEVICE_TYPE_TUN: a TUN/TAP interface + * @NM_DEVICE_TYPE_IP_TUNNEL: an IP tunnel interface * * #NMDeviceType values indicate the type of hardware represented by * an #NMDevice. @@ -176,6 +177,7 @@ typedef enum { NM_DEVICE_TYPE_GENERIC = 14, NM_DEVICE_TYPE_TEAM = 15, NM_DEVICE_TYPE_TUN = 16, + NM_DEVICE_TYPE_IP_TUNNEL = 17, } NMDeviceType; /** diff --git a/libnm/Makefile.am b/libnm/Makefile.am index bf921abd89..4ce9655554 100644 --- a/libnm/Makefile.am +++ b/libnm/Makefile.am @@ -38,6 +38,7 @@ libnminclude_hfiles = \ nm-device-ethernet.h \ nm-device-generic.h \ nm-device-infiniband.h \ + nm-device-ip-tunnel.h \ nm-device-modem.h \ nm-device-olpc-mesh.h \ nm-device-team.h \ @@ -90,6 +91,7 @@ libnm_la_csources = \ nm-device-ethernet.c \ nm-device-generic.c \ nm-device-infiniband.c \ + nm-device-ip-tunnel.c \ nm-device-modem.c \ nm-device-olpc-mesh.c \ nm-device-team.c \ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 95c92965e3..17e7a3523b 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -61,6 +61,7 @@ #include <nm-setting-gsm.h> #include <nm-setting-infiniband.h> #include <nm-setting-ip-config.h> +#include <nm-setting-ip-tunnel.h> #include <nm-setting-ip4-config.h> #include <nm-setting-ip6-config.h> #include <nm-setting-olpc-mesh.h> diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 865cc328df..dbd95922e9 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -858,10 +858,23 @@ libnm_1_0_6 { libnm_1_2_0 { global: nm_access_point_get_last_seen; + nm_connection_get_setting_ip_tunnel; nm_connection_verify_secrets; nm_device_ethernet_get_s390_subchannels; nm_device_get_lldp_neighbors; nm_device_get_metered; + nm_device_ip_tunnel_get_encapsulation_limit; + nm_device_ip_tunnel_get_flow_label; + nm_device_ip_tunnel_get_input_key; + nm_device_ip_tunnel_get_local; + nm_device_ip_tunnel_get_mode; + nm_device_ip_tunnel_get_output_key; + nm_device_ip_tunnel_get_parent; + nm_device_ip_tunnel_get_path_mtu_discovery; + nm_device_ip_tunnel_get_remote; + nm_device_ip_tunnel_get_tos; + nm_device_ip_tunnel_get_ttl; + nm_device_ip_tunnel_get_type; nm_device_get_nm_plugin_missing; nm_device_set_managed; nm_device_tun_get_group; @@ -874,6 +887,7 @@ global: nm_device_tun_get_vnet_hdr; nm_device_wifi_request_scan_options; nm_device_wifi_request_scan_options_async; + nm_ip_tunnel_mode_get_type; nm_lldp_neighbor_get_attr_names; nm_lldp_neighbor_get_attr_string_value; nm_lldp_neighbor_get_attr_type; @@ -904,6 +918,17 @@ global: nm_setting_ip_config_has_dns_options; nm_setting_ip_config_remove_dns_option; nm_setting_ip_config_remove_dns_option_by_value; + nm_setting_ip_tunnel_get_input_key; + nm_setting_ip_tunnel_get_local; + nm_setting_ip_tunnel_get_mode; + nm_setting_ip_tunnel_get_output_key; + nm_setting_ip_tunnel_get_parent; + nm_setting_ip_tunnel_get_path_mtu_discovery; + nm_setting_ip_tunnel_get_remote; + nm_setting_ip_tunnel_get_tos; + nm_setting_ip_tunnel_get_type; + nm_setting_ip_tunnel_get_ttl; + nm_setting_ip_tunnel_new; nm_setting_mac_randomization_get_type; nm_setting_tun_get_group; nm_setting_tun_get_mode; @@ -925,6 +950,7 @@ global: nm_utils_bond_mode_string_to_int; nm_utils_enum_from_str; nm_utils_enum_to_str; + nm_utils_enum_get_values; nm_utils_wifi_2ghz_freqs; nm_utils_wifi_5ghz_freqs; nm_vpn_editor_plugin_load_from_file; diff --git a/libnm/nm-device-ip-tunnel.c b/libnm/nm-device-ip-tunnel.c new file mode 100644 index 0000000000..ad107155b8 --- /dev/null +++ b/libnm/nm-device-ip-tunnel.c @@ -0,0 +1,544 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include <string.h> + +#include <nm-setting-connection.h> +#include <nm-setting-ip-tunnel.h> +#include <nm-utils.h> + +#include "nm-default.h" +#include "nm-device-ip-tunnel.h" +#include "nm-device-private.h" +#include "nm-object-private.h" +#include "nm-core-internal.h" + +G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE) + +#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelPrivate)) + +typedef struct { + NMIPTunnelMode mode; + NMDevice *parent; + char *local; + char *remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; + char *input_key; + char *output_key; + guint8 encap_limit; + guint32 flow_label; +} NMDeviceIPTunnelPrivate; + +enum { + PROP_0, + PROP_MODE, + PROP_PARENT, + PROP_LOCAL, + PROP_REMOTE, + PROP_TTL, + PROP_TOS, + PROP_PATH_MTU_DISCOVERY, + PROP_INPUT_KEY, + PROP_OUTPUT_KEY, + PROP_ENCAPSULATION_LIMIT, + PROP_FLOW_LABEL, + + LAST_PROP +}; + +/** + * nm_device_ip_tunnel_get_mode: + * @device: a #NMDeviceIPTunnel + * + * Returns: the tunneling mode + * + * Since: 1.2 + **/ +NMIPTunnelMode +nm_device_ip_tunnel_get_mode (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->mode; +} + +/** + * nm_device_ip_tunnel_get_parent: + * @device: a #NMDeviceIPTunnel + * + * Returns: (transfer none): the device's parent device + * + * Since: 1.2 + **/ +NMDevice * +nm_device_ip_tunnel_get_parent (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->parent; +} + +/** + * nm_device_ip_tunnel_get_local: + * @device: a #NMDeviceIPTunnel + * + * Returns: the local endpoint of the tunnel + * + * Since: 1.2 + **/ +const char * +nm_device_ip_tunnel_get_local (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->local; +} + +/** + * nm_device_ip_tunnel_get_remote: + * @device: a #NMDeviceIPTunnel + * + * Returns: the remote endpoint of the tunnel + * + * Since: 1.2 + **/ +const char * +nm_device_ip_tunnel_get_remote (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->remote; +} + +/** + * nm_device_ip_tunnel_get_ttl: + * @device: a #NMDeviceIPTunnel + * + * Returns: the TTL assigned to tunneled packets + * + * Since: 1.2 + **/ +guint8 +nm_device_ip_tunnel_get_ttl (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->ttl; +} + +/** + * nm_device_ip_tunnel_get_tos: + * @device: a #NMDeviceIPTunnel + * + * Returns: type of service (IPv4) or traffic class (IPv6) assigned + * to tunneled packets. + * + * Since: 1.2 + **/ +guint8 +nm_device_ip_tunnel_get_tos (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->tos; +} + +/** + * nm_device_ip_tunnel_get_path_mtu_discovery: + * @device: a #NMDeviceIPTunnel + * + * Returns: whether path MTU discovery is enabled + * + * Since: 1.2 + **/ +gboolean +nm_device_ip_tunnel_get_path_mtu_discovery (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), TRUE); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->path_mtu_discovery; +} + +/** + * nm_device_ip_tunnel_get_input_key: + * @device: a #NMDeviceIPTunnel + * + * Returns: the key used for incoming packets + * + * Since: 1.2 + **/ +const char * +nm_device_ip_tunnel_get_input_key (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->input_key; +} + +/** + * nm_device_ip_tunnel_get_output_key: + * @device: a #NMDeviceIPTunnel + * + * Returns: the key used for outgoing packets + * + * Since: 1.2 + **/ +const char * +nm_device_ip_tunnel_get_output_key (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->output_key; +} + +/** + * nm_device_ip_tunnel_get_encapsulation_limit: + * @device: a #NMDeviceIPTunnel + * + * Returns: the maximum permitted encapsulation level + * + * Since: 1.2 + **/ +guint8 +nm_device_ip_tunnel_get_encapsulation_limit (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->encap_limit; +} + +/** + * nm_device_ip_tunnel_get_flow_label: + * @device: a #NMDeviceIPTunnel + * + * Returns: the flow label assigned to tunnel packets + * + * Since: 1.2 + **/ +guint +nm_device_ip_tunnel_get_flow_label (NMDeviceIPTunnel *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0); + + return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->flow_label; +} + +static gboolean +connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not an IP tunnel connection.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type (NMDevice *device) +{ + return NM_TYPE_SETTING_IP_TUNNEL; +} + +/***********************************************************/ + +static void +nm_device_ip_tunnel_init (NMDeviceIPTunnel *device) +{ + _nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_IP_TUNNEL); +} + +static void +init_dbus (NMObject *object) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + const NMPropertiesInfo property_info[] = { + { NM_DEVICE_IP_TUNNEL_PARENT, &priv->parent, NULL, NM_TYPE_DEVICE }, + { NM_DEVICE_IP_TUNNEL_MODE, &priv->mode }, + { NM_DEVICE_IP_TUNNEL_LOCAL, &priv->local }, + { NM_DEVICE_IP_TUNNEL_REMOTE, &priv->remote }, + { NM_DEVICE_IP_TUNNEL_TTL, &priv->ttl }, + { NM_DEVICE_IP_TUNNEL_TOS, &priv->tos }, + { NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, &priv->path_mtu_discovery }, + { NM_DEVICE_IP_TUNNEL_INPUT_KEY, &priv->input_key }, + { NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, &priv->output_key }, + { NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, &priv->encap_limit }, + { NM_DEVICE_IP_TUNNEL_FLOW_LABEL, &priv->flow_label }, + { NULL }, + }; + + NM_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->init_dbus (object); + + _nm_object_register_properties (object, + NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL, + property_info); +} + +static void +finalize (GObject *object) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + + g_free (priv->local); + g_free (priv->remote); + g_free (priv->input_key); + g_free (priv->output_key); + g_clear_object (&priv->parent); + + G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NMDeviceIPTunnel *device = NM_DEVICE_IP_TUNNEL (object); + + switch (prop_id) { + case PROP_PARENT: + g_value_set_object (value, nm_device_ip_tunnel_get_parent (device)); + break; + case PROP_MODE: + g_value_set_uint (value, nm_device_ip_tunnel_get_mode (device)); + break; + case PROP_LOCAL: + g_value_set_string (value, nm_device_ip_tunnel_get_local (device)); + break; + case PROP_REMOTE: + g_value_set_string (value, nm_device_ip_tunnel_get_remote (device)); + break; + case PROP_TTL: + g_value_set_uint (value, nm_device_ip_tunnel_get_ttl (device)); + break; + case PROP_TOS: + g_value_set_uint (value, nm_device_ip_tunnel_get_tos (device)); + break; + case PROP_PATH_MTU_DISCOVERY: + g_value_set_boolean (value, nm_device_ip_tunnel_get_path_mtu_discovery (device)); + break; + case PROP_INPUT_KEY: + g_value_set_string (value, nm_device_ip_tunnel_get_input_key (device)); + break; + case PROP_OUTPUT_KEY: + g_value_set_string (value, nm_device_ip_tunnel_get_output_key (device)); + break; + case PROP_ENCAPSULATION_LIMIT: + g_value_set_uint (value, nm_device_ip_tunnel_get_encapsulation_limit (device)); + break; + case PROP_FLOW_LABEL: + g_value_set_uint (value, nm_device_ip_tunnel_get_flow_label (device)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *bond_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bond_class); + NMObjectClass *nm_object_class = NM_OBJECT_CLASS (bond_class); + NMDeviceClass *device_class = NM_DEVICE_CLASS (bond_class); + + g_type_class_add_private (bond_class, sizeof (NMDeviceIPTunnelPrivate)); + + _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL); + + /* virtual methods */ + object_class->finalize = finalize; + object_class->get_property = get_property; + + nm_object_class->init_dbus = init_dbus; + + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; + + /* properties */ + + /** + * NMDeviceIPTunnel:mode: + * + * The tunneling mode of the device. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_MODE, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:parent: + * + * The devices's parent device. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_object (NM_DEVICE_IP_TUNNEL_PARENT, "", "", + NM_TYPE_DEVICE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:local: + * + * The local endpoint of the tunnel. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_LOCAL, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_LOCAL, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:remote: + * + * The remote endpoint of the tunnel. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_REMOTE, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_REMOTE, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:ttl: + * + * The TTL assigned to tunneled packets. 0 is a special value + * meaning that packets inherit the TTL value + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_TTL, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TTL, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:tos: + * + * The type of service (IPv4) or traffic class (IPv6) assigned to + * tunneled packets. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_TOS, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TOS, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:path-mtu-discovery: + * + * Whether path MTU discovery is enabled on this tunnel. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_PATH_MTU_DISCOVERY, + g_param_spec_boolean (NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:parent: + * + * The key used for tunneled input packets, if applicable. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_INPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_INPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:output-key: + * + * The key used for tunneled output packets, if applicable. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_OUTPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:encapsulation-limit: + * + * How many additional levels of encapsulation are permitted to + * be prepended to packets. This property applies only to IPv6 + * tunnels. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_ENCAPSULATION_LIMIT, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceIPTunnel:flow-label: + * + * The flow label to assign to tunnel packets. This property + * applies only to IPv6 tunnels. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_FLOW_LABEL, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "", + 0, (1 << 20) - 1, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm/nm-device-ip-tunnel.h b/libnm/nm-device-ip-tunnel.h new file mode 100644 index 0000000000..820eab16dc --- /dev/null +++ b/libnm/nm-device-ip-tunnel.h @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_IP_TUNNEL_H__ +#define __NM_DEVICE_IP_TUNNEL_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include <nm-device.h> + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type ()) +#define NM_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) +#define NM_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) +#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) + +#define NM_DEVICE_IP_TUNNEL_MODE "mode" +#define NM_DEVICE_IP_TUNNEL_PARENT "parent" +#define NM_DEVICE_IP_TUNNEL_LOCAL "local" +#define NM_DEVICE_IP_TUNNEL_REMOTE "remote" +#define NM_DEVICE_IP_TUNNEL_TTL "ttl" +#define NM_DEVICE_IP_TUNNEL_TOS "tos" +#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery" +#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key" +#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key" +#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" +#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" + +struct _NMDeviceIPTunnel { + NMDevice parent; +}; + +typedef struct { + NMDeviceClass parent; + + /*< private >*/ + gpointer padding[4]; +} NMDeviceIPTunnelClass; + +NM_AVAILABLE_IN_1_2 +GType nm_device_ip_tunnel_get_type (void); + +NM_AVAILABLE_IN_1_2 +NMDevice * nm_device_ip_tunnel_get_parent (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +NMIPTunnelMode nm_device_ip_tunnel_get_mode (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +const char * nm_device_ip_tunnel_get_local (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +const char * nm_device_ip_tunnel_get_remote (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +guint8 nm_device_ip_tunnel_get_ttl (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +guint8 nm_device_ip_tunnel_get_tos (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +gboolean nm_device_ip_tunnel_get_path_mtu_discovery (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +const char * nm_device_ip_tunnel_get_input_key (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +const char * nm_device_ip_tunnel_get_output_key (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +guint8 nm_device_ip_tunnel_get_encapsulation_limit (NMDeviceIPTunnel *device); +NM_AVAILABLE_IN_1_2 +guint nm_device_ip_tunnel_get_flow_label (NMDeviceIPTunnel *device); + +G_END_DECLS + +#endif /* __NM_DEVICE_IP_TUNNEL_H__ */ diff --git a/libnm/nm-device.c b/libnm/nm-device.c index e6e5126f51..3ca08c55ce 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -41,6 +41,7 @@ #include "nm-device-bridge.h" #include "nm-device-vlan.h" #include "nm-device-generic.h" +#include "nm-device-ip-tunnel.h" #include "nm-device.h" #include "nm-device-private.h" #include "nm-dhcp4-config.h" @@ -365,6 +366,8 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype) return NM_TYPE_DEVICE_GENERIC; case NM_DEVICE_TYPE_TUN: return NM_TYPE_DEVICE_TUN; + case NM_DEVICE_TYPE_IP_TUNNEL: + return NM_TYPE_DEVICE_IP_TUNNEL; default: g_warning ("Unknown device type %d", dtype); return G_TYPE_INVALID; diff --git a/libnm/nm-types.h b/libnm/nm-types.h index 334e4a17b7..f69deffaec 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -37,6 +37,7 @@ typedef struct _NMDeviceBt NMDeviceBt; typedef struct _NMDeviceEthernet NMDeviceEthernet; typedef struct _NMDeviceGeneric NMDeviceGeneric; typedef struct _NMDeviceInfiniband NMDeviceInfiniband; +typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; typedef struct _NMDeviceTeam NMDeviceTeam; diff --git a/po/POTFILES.in b/po/POTFILES.in index ca4b76ab1f..a451d8dd00 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -65,6 +65,7 @@ libnm-core/nm-setting-infiniband.c libnm-core/nm-setting-ip-config.c libnm-core/nm-setting-ip4-config.c libnm-core/nm-setting-ip6-config.c +libnm-core/nm-setting-ip-tunnel.c libnm-core/nm-setting-olpc-mesh.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c @@ -119,6 +120,7 @@ libnm/nm-device-ethernet.c libnm/nm-device-generic.c libnm/nm-device-tun.c libnm/nm-device-infiniband.c +libnm/nm-device-ip-tunnel.c libnm/nm-device-modem.c libnm/nm-device-olpc-mesh.c libnm/nm-device-team.c @@ -148,6 +150,7 @@ src/devices/nm-device-bridge.c src/devices/nm-device-ethernet.c src/devices/nm-device-ethernet-utils.c src/devices/nm-device-infiniband.c +src/devices/nm-device-ip-tunnel.c src/devices/nm-device-tun.c src/devices/nm-device-vlan.c src/devices/team/nm-device-team.c diff --git a/src/Makefile.am b/src/Makefile.am index 89681f1970..e4b2cb090c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -204,8 +204,8 @@ nm_device_sources = \ devices/nm-device-bond.c \ devices/nm-device-bridge.c \ devices/nm-device-ethernet.c \ - devices/nm-device-gre.c \ devices/nm-device-infiniband.c \ + devices/nm-device-ip-tunnel.c \ devices/nm-device-macvlan.c \ devices/nm-device-tun.c \ devices/nm-device-veth.c \ @@ -217,8 +217,8 @@ nm_device_headers = \ devices/nm-device-bond.h \ devices/nm-device-bridge.h \ devices/nm-device-ethernet.h \ - devices/nm-device-gre.h \ devices/nm-device-infiniband.h \ + devices/nm-device-ip-tunnel.h \ devices/nm-device-macvlan.h \ devices/nm-device-tun.h \ devices/nm-device-veth.h \ diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c deleted file mode 100644 index 9b9ffc9be1..0000000000 --- a/src/devices/nm-device-gre.c +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2013 Red Hat, Inc. - */ - -#include "config.h" - -#include <string.h> -#include <arpa/inet.h> - -#include "nm-device-gre.h" -#include "nm-device-private.h" -#include "nm-default.h" -#include "nm-manager.h" -#include "nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" - -#include "nmdbus-device-gre.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceGre); - -G_DEFINE_TYPE (NMDeviceGre, nm_device_gre, NM_TYPE_DEVICE_GENERIC) - -#define NM_DEVICE_GRE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GRE, NMDeviceGrePrivate)) - -typedef struct { - NMPlatformLnkGre props; -} NMDeviceGrePrivate; - -enum { - PROP_0, - PROP_PARENT, - PROP_INPUT_FLAGS, - PROP_OUTPUT_FLAGS, - PROP_INPUT_KEY, - PROP_OUTPUT_KEY, - PROP_LOCAL, - PROP_REMOTE, - PROP_TTL, - PROP_TOS, - PROP_PATH_MTU_DISCOVERY, - - LAST_PROP -}; - -/**************************************************************/ - -static void -update_properties (NMDevice *device) -{ - NMDeviceGre *self = NM_DEVICE_GRE (device); - NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (self); - GObject *object = G_OBJECT (device); - const NMPlatformLnkGre *props; - - props = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); - if (!props) { - _LOGW (LOGD_HW, "could not read gre properties"); - return; - } - - g_object_freeze_notify (object); - - if (priv->props.parent_ifindex != props->parent_ifindex) - g_object_notify (object, NM_DEVICE_GRE_PARENT); - if (priv->props.input_flags != props->input_flags) - g_object_notify (object, NM_DEVICE_GRE_INPUT_FLAGS); - if (priv->props.output_flags != props->output_flags) - g_object_notify (object, NM_DEVICE_GRE_OUTPUT_FLAGS); - if (priv->props.input_key != props->input_key) - g_object_notify (object, NM_DEVICE_GRE_INPUT_KEY); - if (priv->props.output_key != props->output_key) - g_object_notify (object, NM_DEVICE_GRE_OUTPUT_KEY); - if (priv->props.local != props->local) - g_object_notify (object, NM_DEVICE_GRE_LOCAL); - if (priv->props.remote != props->remote) - g_object_notify (object, NM_DEVICE_GRE_REMOTE); - if (priv->props.ttl != props->ttl) - g_object_notify (object, NM_DEVICE_GRE_TTL); - if (priv->props.tos != props->tos) - g_object_notify (object, NM_DEVICE_GRE_TOS); - if (priv->props.path_mtu_discovery != props->path_mtu_discovery) - g_object_notify (object, NM_DEVICE_GRE_PATH_MTU_DISCOVERY); - - priv->props = *props; - - g_object_thaw_notify (object); -} - -static void -link_changed (NMDevice *device, NMPlatformLink *info) -{ - NM_DEVICE_CLASS (nm_device_gre_parent_class)->link_changed (device, info); - update_properties (device); -} - -/**************************************************************/ - -static void -nm_device_gre_init (NMDeviceGre *self) -{ -} - -static void -constructed (GObject *object) -{ - update_properties (NM_DEVICE (object)); - - G_OBJECT_CLASS (nm_device_gre_parent_class)->constructed (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (object); - char buf[INET_ADDRSTRLEN]; - NMDevice *parent; - - switch (prop_id) { - case PROP_PARENT: - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); - nm_utils_g_value_set_object_path (value, parent); - break; - case PROP_INPUT_FLAGS: - g_value_set_uint (value, priv->props.input_flags); - break; - case PROP_OUTPUT_FLAGS: - g_value_set_uint (value, priv->props.output_flags); - break; - case PROP_INPUT_KEY: - g_value_set_uint (value, priv->props.input_key); - break; - case PROP_OUTPUT_KEY: - g_value_set_uint (value, priv->props.output_key); - break; - case PROP_LOCAL: - g_value_set_string (value, inet_ntop (AF_INET, &priv->props.local, buf, sizeof (buf))); - break; - case PROP_REMOTE: - g_value_set_string (value, inet_ntop (AF_INET, &priv->props.remote, buf, sizeof (buf))); - break; - case PROP_TTL: - g_value_set_uchar (value, priv->props.ttl); - break; - case PROP_TOS: - g_value_set_uchar (value, priv->props.tos); - break; - case PROP_PATH_MTU_DISCOVERY: - g_value_set_boolean (value, priv->props.path_mtu_discovery); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_device_gre_class_init (NMDeviceGreClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMDeviceGrePrivate)); - - object_class->constructed = constructed; - object_class->get_property = get_property; - - device_class->link_changed = link_changed; - - /* properties */ - g_object_class_install_property - (object_class, PROP_PARENT, - g_param_spec_string (NM_DEVICE_GRE_PARENT, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_INPUT_FLAGS, - g_param_spec_uint (NM_DEVICE_GRE_INPUT_FLAGS, "", "", - 0, G_MAXUINT16, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_OUTPUT_FLAGS, - g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_FLAGS, "", "", - 0, G_MAXUINT16, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_INPUT_KEY, - g_param_spec_uint (NM_DEVICE_GRE_INPUT_KEY, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_OUTPUT_KEY, - g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_KEY, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_LOCAL, - g_param_spec_string (NM_DEVICE_GRE_LOCAL, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_REMOTE, - g_param_spec_string (NM_DEVICE_GRE_REMOTE, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_TTL, - g_param_spec_uchar (NM_DEVICE_GRE_TTL, "", "", - 0, 255, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_TOS, - g_param_spec_uchar (NM_DEVICE_GRE_TOS, "", "", - 0, 255, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_PATH_MTU_DISCOVERY, - g_param_spec_boolean (NM_DEVICE_GRE_PATH_MTU_DISCOVERY, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), - NMDBUS_TYPE_DEVICE_GRE_SKELETON, - NULL); -} - -/*************************************************************/ - -#define NM_TYPE_GRE_FACTORY (nm_gre_factory_get_type ()) -#define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory)) - -static NMDevice * -create_device (NMDeviceFactory *factory, - const char *iface, - NMPlatformLink *plink, - NMConnection *connection, - gboolean *out_ignore) -{ - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, - NM_DEVICE_IFACE, iface, - NM_DEVICE_TYPE_DESC, "Gre", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP), - factory_iface->create_device = create_device; - ) - diff --git a/src/devices/nm-device-gre.h b/src/devices/nm-device-gre.h deleted file mode 100644 index 7e2d105c4b..0000000000 --- a/src/devices/nm-device-gre.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_GRE_H__ -#define __NETWORKMANAGER_DEVICE_GRE_H__ - -#include "nm-device-generic.h" - -G_BEGIN_DECLS - -#define NM_TYPE_DEVICE_GRE (nm_device_gre_get_type ()) -#define NM_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGre)) -#define NM_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_GRE, NMDeviceGreClass)) -#define NM_IS_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_GRE)) -#define NM_IS_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_GRE)) -#define NM_DEVICE_GRE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGreClass)) - -#define NM_DEVICE_GRE_PARENT "parent" -#define NM_DEVICE_GRE_INPUT_FLAGS "input-flags" -#define NM_DEVICE_GRE_OUTPUT_FLAGS "output-flags" -#define NM_DEVICE_GRE_INPUT_KEY "input-key" -#define NM_DEVICE_GRE_OUTPUT_KEY "output-key" -#define NM_DEVICE_GRE_LOCAL "local" -#define NM_DEVICE_GRE_REMOTE "remote" -#define NM_DEVICE_GRE_TTL "ttl" -#define NM_DEVICE_GRE_TOS "tos" -#define NM_DEVICE_GRE_PATH_MTU_DISCOVERY "path-mtu-discovery" - -typedef NMDeviceGeneric NMDeviceGre; -typedef NMDeviceGenericClass NMDeviceGreClass; - -GType nm_device_gre_get_type (void); - -G_END_DECLS - -#endif /* NM_DEVICE_GRE_H */ diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c new file mode 100644 index 0000000000..746fb170d0 --- /dev/null +++ b/src/devices/nm-device-ip-tunnel.c @@ -0,0 +1,971 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include <string.h> +#include <netinet/in.h> +#include <linux/if.h> +#include <linux/ip.h> +#include <linux/if_tunnel.h> + +#include "nm-device-ip-tunnel.h" +#include "nm-device-private.h" +#include "nm-default.h" +#include "nm-manager.h" +#include "nm-platform.h" +#include "nm-device-factory.h" +#include "nm-core-internal.h" +#include "nm-connection-provider.h" +#include "nm-activation-request.h" + +#include "nmdbus-device-ip-tunnel.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceIPTunnel); + +G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE) + +#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelPrivate)) + +typedef struct { + NMIPTunnelMode mode; + NMDevice *parent; + int parent_ifindex; + char *local; + char *remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; + int addr_family; + char *input_key; + char *output_key; + guint8 encap_limit; + guint32 flow_label; +} NMDeviceIPTunnelPrivate; + +enum { + PROP_0, + PROP_MODE, + PROP_PARENT, + PROP_LOCAL, + PROP_REMOTE, + PROP_TTL, + PROP_TOS, + PROP_PATH_MTU_DISCOVERY, + PROP_INPUT_KEY, + PROP_OUTPUT_KEY, + PROP_ENCAPSULATION_LIMIT, + PROP_FLOW_LABEL, + + LAST_PROP +}; + +/**************************************************************/ + +static gboolean +address_equal_pp (int family, const char *a, const char *b) +{ + char buffer1[sizeof (struct in6_addr)] = { }; + char buffer2[sizeof (struct in6_addr)] = { }; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + if (a) + inet_pton (family, a, buffer1); + if (b) + inet_pton (family, b, buffer2); + + return !memcmp (buffer1, buffer2, + family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); +} + +static gboolean +address_equal_pn (int family, const char *a, const void *b) +{ + char buffer1[sizeof (struct in6_addr)] = { }; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + if (a) + inet_pton (family, a, buffer1); + + return !memcmp (buffer1, b, + family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); + +} + +static void +update_properties (NMDevice *device) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + GObject *object = G_OBJECT (device); + NMDevice *parent; + int parent_ifindex; + in_addr_t local4, remote4; + struct in6_addr local6, remote6; + guint8 ttl = 0, tos = 0, encap_limit = 0; + gboolean pmtud = FALSE; + guint32 flow_label = 0; + char *key; + + if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { + const NMPlatformLnkGre *lnk; + + lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "gre"); + return; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + + if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->input_key); + if (g_strcmp0 (priv->input_key, key)) { + g_free (priv->input_key); + priv->input_key = key; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); + } else + g_free (key); + } else { + if (priv->input_key) { + g_clear_pointer (&priv->input_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); + } + } + + if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->output_key); + if (g_strcmp0 (priv->output_key, key)) { + g_free (priv->output_key); + priv->output_key = key; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); + } else + g_free (key); + } else { + if (priv->output_key) { + g_clear_pointer (&priv->output_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); + } + } + } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { + const NMPlatformLnkSit *lnk; + + lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "sit"); + return; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { + const NMPlatformLnkIpIp *lnk; + + lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "ipip"); + return; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 + || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { + const NMPlatformLnkIp6Tnl *lnk; + + lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "ip6tnl"); + return; + } + + parent_ifindex = lnk->parent_ifindex; + local6 = lnk->local; + remote6 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tclass; + encap_limit = lnk->encap_limit; + flow_label = lnk->flow_label; + } else + g_return_if_reached (); + + if (priv->parent_ifindex != parent_ifindex) { + g_clear_object (&priv->parent); + priv->parent_ifindex = parent_ifindex; + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (parent) + priv->parent = g_object_ref (parent); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); + } + + if (priv->addr_family == AF_INET) { + if (!address_equal_pn (AF_INET, priv->local, &local4)) { + g_clear_pointer (&priv->local, g_free); + if (local4) + priv->local = g_strdup (nm_utils_inet4_ntop (local4, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); + } + + if (!address_equal_pn (AF_INET, priv->remote, &remote4)) { + g_clear_pointer (&priv->remote, g_free); + if (remote4) + priv->remote = g_strdup (nm_utils_inet4_ntop (remote4, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); + } + } else { + if (!address_equal_pn (AF_INET6, priv->local, &local6)) { + g_clear_pointer (&priv->local, g_free); + if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any))) + priv->local = g_strdup (nm_utils_inet6_ntop (&local6, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); + } + + if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) { + g_clear_pointer (&priv->remote, g_free); + if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any))) + priv->remote = g_strdup (nm_utils_inet6_ntop (&remote6, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); + } + } + + if (priv->ttl != ttl) { + priv->ttl = ttl; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_TTL); + } + + if (priv->tos != tos) { + priv->tos = tos; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_TOS); + } + + if (priv->path_mtu_discovery != pmtud) { + priv->path_mtu_discovery = pmtud; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY); + } + + if (priv->encap_limit != encap_limit) { + priv->encap_limit = encap_limit; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT); + } + + if (priv->flow_label != flow_label) { + priv->flow_label = flow_label; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL); + } +} + +static void +link_changed (NMDevice *device, NMPlatformLink *info) +{ + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->link_changed (device, info); + update_properties (device); +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingIPTunnel *s_ip_tunnel; + + nm_utils_complete_generic (connection, + NM_SETTING_IP_TUNNEL_SETTING_NAME, + existing_connections, + NULL, + _("IP tunnel connection"), + NULL, + TRUE); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + if (!s_ip_tunnel) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'tunnel' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + NMSettingIPTunnel *s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + NMDevice *parent = NULL; + const char *setting_parent, *new_parent; + + if (!s_ip_tunnel) { + s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new (); + nm_connection_add_setting (connection, (NMSetting *) s_ip_tunnel); + } + + update_properties (device); + + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_MODE, priv->mode, NULL); + + if (priv->parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex); + + /* Update parent in the connection; default to parent's interface name */ + if (parent) { + new_parent = nm_device_get_iface (parent); + setting_parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), + setting_parent); + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, new_parent, NULL); + } else + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, NULL, NULL); + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_local (s_ip_tunnel), + priv->local)) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_LOCAL, priv->local, NULL); + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_remote (s_ip_tunnel), + priv->remote)) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_REMOTE, priv->remote, NULL); + + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TTL, priv->ttl, NULL); + + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TOS, priv->tos, NULL); + + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, + priv->path_mtu_discovery, + NULL); + } + + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, + priv->encap_limit, + NULL); + } + + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_FLOW_LABEL, + priv->flow_label, + NULL); + } + + if (priv->mode == NM_IP_TUNNEL_MODE_GRE || priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) { + if (g_strcmp0 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), priv->input_key)) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_INPUT_KEY, + priv->input_key, + NULL); + } + if (g_strcmp0 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), priv->output_key)) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_OUTPUT_KEY, + priv->output_key, + NULL); + } + } +} + +static gboolean +realize (NMDevice *self, NMPlatformLink *plink, GError **error) +{ + update_properties (self); + return TRUE; +} + +static gboolean +match_parent (NMDevice *dev_parent, const char *setting_parent) +{ + g_return_val_if_fail (setting_parent, FALSE); + + if (!dev_parent) + return FALSE; + + if (nm_utils_is_uuid (setting_parent)) { + NMActRequest *parent_req; + NMConnection *parent_connection; + + /* If the parent is a UUID, the connection matches if our parent + * device has that connection activated. + */ + parent_req = nm_device_get_act_request (dev_parent); + if (!parent_req) + return FALSE; + + parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req)); + if (!parent_connection) + return FALSE; + + if (g_strcmp0 (setting_parent, nm_connection_get_uuid (parent_connection)) != 0) + return FALSE; + } else { + /* interface name */ + if (g_strcmp0 (setting_parent, nm_device_get_ip_iface (dev_parent)) != 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + NMSettingIPTunnel *s_ip_tunnel; + const char *parent; + + if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + if (!s_ip_tunnel) + return FALSE; + + update_properties (device); + + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); + if (parent) { + if (!match_parent (priv->parent, parent)) + return FALSE; + } + + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + return FALSE; + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_local (s_ip_tunnel), + priv->local)) + return FALSE; + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_remote (s_ip_tunnel), + priv->remote)) + return FALSE; + + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + return FALSE; + + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + return FALSE; + + if (priv->addr_family == AF_INET) { + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) + return FALSE; + } else { + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + return FALSE; + + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + return FALSE; + } + + return TRUE; +} + +static NMIPTunnelMode +platform_link_to_tunnel_mode (const NMPlatformLink *link) +{ + const NMPlatformLnkIp6Tnl *lnk; + + switch (link->type) { + case NM_LINK_TYPE_GRE: + return NM_IP_TUNNEL_MODE_GRE; + case NM_LINK_TYPE_IP6TNL: + lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, link->ifindex, NULL); + if (lnk->proto == IPPROTO_IPIP) + return NM_IP_TUNNEL_MODE_IPIP6; + else if (lnk->proto == IPPROTO_IPV6) + return NM_IP_TUNNEL_MODE_IP6IP6; + else + return NM_IP_TUNNEL_MODE_UKNOWN; + case NM_LINK_TYPE_IPIP: + return NM_IP_TUNNEL_MODE_IPIP; + case NM_LINK_TYPE_SIT: + return NM_IP_TUNNEL_MODE_SIT; + default: + g_return_val_if_reached (NM_IP_TUNNEL_MODE_UKNOWN); + } +} + +/**************************************************************/ + +static void +nm_device_ip_tunnel_init (NMDeviceIPTunnel *self) +{ +} + +static void +constructed (GObject *object) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + + if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 + || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) + priv->addr_family = AF_INET6; + else + priv->addr_family = AF_INET; + + G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->constructed (object); +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + NMPlatformLink *out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMSettingIPTunnel *s_ip_tunnel; + NMPlatformError plerr; + NMPlatformLnkGre lnk_gre = { }; + NMPlatformLnkSit lnk_sit = { }; + NMPlatformLnkIpIp lnk_ipip = { }; + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + const char *str; + gint64 val; + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + g_assert (out_plink); + + switch (nm_setting_ip_tunnel_get_mode (s_ip_tunnel)) { + case NM_IP_TUNNEL_MODE_GRE: + if (parent) + lnk_gre.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_gre.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_gre.remote); + + lnk_gre.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_gre.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_gre.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_gre.input_key = val; + lnk_gre.input_flags = NM_GRE_KEY; + } + + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_gre.output_key = val; + lnk_gre.output_flags = NM_GRE_KEY; + } + + plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create GRE interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_SIT: + if (parent) + lnk_sit.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_sit.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_sit.remote); + + lnk_sit.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_sit.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create SIT interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_IPIP: + if (parent) + lnk_ipip.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_ipip.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_ipip.remote); + + lnk_ipip.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_ipip.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IPIP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_IPIP6: + case NM_IP_TUNNEL_MODE_IP6IP6: + if (parent) + lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET6, str, &lnk_ip6tnl.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET6, str, &lnk_ip6tnl.remote); + + lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel); + lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); + lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; + + plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IPIP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + default: + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IP tunnel interface '%s' for '%s': mode %d not supported", + iface, + nm_connection_get_id (connection), + (int) nm_setting_ip_tunnel_get_mode (s_ip_tunnel)); + return FALSE; + } + + return TRUE; +} + +static void +setup (NMDevice *device, NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup (device, plink); + + update_properties (device); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + NMDevice *parent; + + switch (prop_id) { + case PROP_MODE: + g_value_set_uint (value, priv->mode); + break; + case PROP_PARENT: + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex); + nm_utils_g_value_set_object_path (value, parent); + break; + case PROP_LOCAL: + g_value_set_string (value, priv->local); + break; + case PROP_REMOTE: + g_value_set_string (value, priv->remote); + break; + case PROP_TTL: + g_value_set_uchar (value, priv->ttl); + break; + case PROP_TOS: + g_value_set_uchar (value, priv->tos); + break; + case PROP_PATH_MTU_DISCOVERY: + g_value_set_boolean (value, priv->path_mtu_discovery); + break; + case PROP_INPUT_KEY: + g_value_set_string (value, priv->input_key); + break; + case PROP_OUTPUT_KEY: + g_value_set_string (value, priv->output_key); + break; + case PROP_ENCAPSULATION_LIMIT: + g_value_set_uchar (value, priv->encap_limit); + break; + case PROP_FLOW_LABEL: + g_value_set_uint (value, priv->flow_label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MODE: + priv->mode = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMDeviceIPTunnelPrivate)); + + object_class->constructed = constructed; + object_class->get_property = get_property; + object_class->set_property = set_property; + + device_class->link_changed = link_changed; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->create_and_realize = create_and_realize; + device_class->realize = realize; + device_class->setup = setup; + + device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME; + + /* properties */ + g_object_class_install_property + (object_class, PROP_MODE, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /* properties */ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_LOCAL, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_LOCAL, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_REMOTE, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_REMOTE, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_TTL, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TTL, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_TOS, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TOS, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_PATH_MTU_DISCOVERY, + g_param_spec_boolean (NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_INPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_INPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_OUTPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_ENCAPSULATION_LIMIT, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_FLOW_LABEL, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "", + 0, (1 << 20) - 1, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_IPTUNNEL_SKELETON, + NULL); +} +/*************************************************************/ + +#define NM_TYPE_IP_TUNNEL_FACTORY (nm_ip_tunnel_factory_get_type ()) +#define NM_IP_TUNNEL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP_TUNNEL_FACTORY, NMIPTunnelFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + NMSettingIPTunnel *s_ip_tunnel; + NMIPTunnelMode mode; + + if (connection) { + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); + } else + mode = platform_link_to_tunnel_mode (plink); + + if (mode == NM_IP_TUNNEL_MODE_UKNOWN) + return NULL; + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_IP_TUNNEL, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "IPTunnel", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_IP_TUNNEL, + NM_DEVICE_IP_TUNNEL_MODE, mode, + NULL); +} + +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingIPTunnel *s_ip_tunnel; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + return nm_setting_ip_tunnel_get_parent (s_ip_tunnel); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingIPTunnel *s_ip_tunnel; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + if (nm_setting_ip_tunnel_get_parent (s_ip_tunnel) && !parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + + return g_strdup (ifname); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (IP_TUNNEL, IPTunnel, ip_tunnel, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_SIT, NM_LINK_TYPE_IPIP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_IP_TUNNEL_SETTING_NAME), + factory_iface->create_device = create_device; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; +) diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h new file mode 100644 index 0000000000..11cb5bce3b --- /dev/null +++ b/src/devices/nm-device-ip-tunnel.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ +#define __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ + +#include "nm-core-types.h" +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type ()) +#define NM_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) +#define NM_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) +#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) + +#define NM_DEVICE_IP_TUNNEL_MODE "mode" +#define NM_DEVICE_IP_TUNNEL_PARENT "parent" +#define NM_DEVICE_IP_TUNNEL_LOCAL "local" +#define NM_DEVICE_IP_TUNNEL_REMOTE "remote" +#define NM_DEVICE_IP_TUNNEL_TTL "ttl" +#define NM_DEVICE_IP_TUNNEL_TOS "tos" +#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery" +#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key" +#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key" +#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" +#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" + +typedef struct { + NMDevice parent; +} NMDeviceIPTunnel; + +typedef struct { + NMDeviceClass parent; +} NMDeviceIPTunnelClass; + +GType nm_device_ip_tunnel_get_type (void); + +G_END_DECLS + +#endif /* NM_DEVICE_IP_TUNNEL_H */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 6a78ed4b1a..459d4ac664 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -760,6 +760,8 @@ nm_device_get_priority (NMDevice *self) return 600; case NM_DEVICE_TYPE_OLPC_MESH: return 650; + case NM_DEVICE_TYPE_IP_TUNNEL: + return 675; case NM_DEVICE_TYPE_MODEM: return 700; case NM_DEVICE_TYPE_BT: diff --git a/src/nm-types.h b/src/nm-types.h index 6dbd3b3b45..16ae6fa7b4 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -108,10 +108,13 @@ typedef enum { NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IPIP, NM_LINK_TYPE_LOOPBACK, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP, NM_LINK_TYPE_OPENVSWITCH, + NM_LINK_TYPE_SIT, NM_LINK_TYPE_TAP, NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, @@ -135,7 +138,10 @@ typedef enum { NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_INFINIBAND, + NMP_OBJECT_TYPE_LNK_IP6TNL, + NMP_OBJECT_TYPE_LNK_IPIP, NMP_OBJECT_TYPE_LNK_MACVLAN, + NMP_OBJECT_TYPE_LNK_SIT, NMP_OBJECT_TYPE_LNK_VLAN, NMP_OBJECT_TYPE_LNK_VXLAN, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index b79aa76767..354641fee8 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -86,10 +86,29 @@ #define IFLA_MACVLAN_FLAGS 2 #define __IFLA_MACVLAN_MAX 3 +#define IFLA_IPTUN_LINK 1 +#define IFLA_IPTUN_LOCAL 2 +#define IFLA_IPTUN_REMOTE 3 +#define IFLA_IPTUN_TTL 4 +#define IFLA_IPTUN_TOS 5 +#define IFLA_IPTUN_ENCAP_LIMIT 6 +#define IFLA_IPTUN_FLOWINFO 7 +#define IFLA_IPTUN_FLAGS 8 +#define IFLA_IPTUN_PROTO 9 +#define IFLA_IPTUN_PMTUDISC 10 +#define __IFLA_IPTUN_MAX 19 +#ifndef IFLA_IPTUN_MAX +#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +#endif + #ifndef MACVLAN_FLAG_NOPROMISC #define MACVLAN_FLAG_NOPROMISC 1 #endif +#define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000 +#define IP6_FLOWINFO_TCLASS_SHIFT 20 +#define IP6_FLOWINFO_FLOWLABEL_MASK 0x000FFFFF + /*********************************************************************************************/ #define _NMLOG_PREFIX_NAME "platform-linux" @@ -118,6 +137,8 @@ } \ } G_STMT_END +#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" + /****************************************************************** * Forward declarations and enums ******************************************************************/ @@ -314,10 +335,13 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, + { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, + { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL }, { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, + { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, @@ -611,6 +635,10 @@ _linktype_get_type (NMPlatform *platform, return NM_LINK_TYPE_LOOPBACK; else if (arptype == ARPHRD_INFINIBAND) return NM_LINK_TYPE_INFINIBAND; + else if (arptype == ARPHRD_SIT) + return NM_LINK_TYPE_SIT; + else if (arptype == ARPHRD_TUNNEL6) + return NM_LINK_TYPE_IP6TNL; if (ifname) { gs_free char *driver = NULL; @@ -821,10 +849,10 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) props = &obj->lnk_gre; props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0; - props->input_flags = tb[IFLA_GRE_IFLAGS] ? nla_get_u16 (tb[IFLA_GRE_IFLAGS]) : 0; - props->output_flags = tb[IFLA_GRE_OFLAGS] ? nla_get_u16 (tb[IFLA_GRE_OFLAGS]) : 0; - props->input_key = (props->input_flags & GRE_KEY) && tb[IFLA_GRE_IKEY] ? nla_get_u32 (tb[IFLA_GRE_IKEY]) : 0; - props->output_key = (props->output_flags & GRE_KEY) && tb[IFLA_GRE_OKEY] ? nla_get_u32 (tb[IFLA_GRE_OKEY]) : 0; + props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0; + props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0; + props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0; + props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0; props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0; props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0; props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0; @@ -897,6 +925,97 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) /*****************************************************************************/ static NMPObject * +_parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIp6Tnl *props; + guint32 flowinfo; + + if (!info_data || g_strcmp0 (kind, "ip6tnl")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); + props = &obj->lnk_ip6tnl; + + if (tb[IFLA_IPTUN_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); + if (tb[IFLA_IPTUN_LOCAL]) + memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + if (tb[IFLA_IPTUN_REMOTE]) + memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + if (tb[IFLA_IPTUN_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); + if (tb[IFLA_IPTUN_ENCAP_LIMIT]) + props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]); + if (tb[IFLA_IPTUN_FLOWINFO]) { + flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO])); + props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; + props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; + } + if (tb[IFLA_IPTUN_PROTO]) + props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]); + + return obj; +} + +/*****************************************************************************/ + +static NMPObject * +_parse_lnk_ipip (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, + [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, + [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIpIp *props; + + if (!info_data || g_strcmp0 (kind, "ipip")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL); + props = &obj->lnk_ipip; + + props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0; + props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0; + props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0; + props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0; + props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0; + props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]); + + return obj; +} + +/*****************************************************************************/ + +static NMPObject * _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) { static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = { @@ -948,6 +1067,48 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static NMPObject * +_parse_lnk_sit (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, + [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, + [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkSit *props; + + if (!info_data || g_strcmp0 (kind, "sit")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL); + props = &obj->lnk_sit; + + props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0; + props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0; + props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0; + props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0; + props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0; + props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]); + props->flags = tb[IFLA_IPTUN_FLAGS] ? nla_get_u16 (tb[IFLA_IPTUN_FLAGS]) : 0; + props->proto = tb[IFLA_IPTUN_PROTO] ? nla_get_u8 (tb[IFLA_IPTUN_PROTO]) : 0; + + return obj; +} + +/*****************************************************************************/ + static gboolean _vlan_qos_mapping_from_nla (struct nlattr *nlattr, const NMVlanQosMapping **out_map, @@ -1325,9 +1486,18 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_INFINIBAND: lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_IP6TNL: + lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_IPIP: + lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_MACVLAN: lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_SIT: + lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; @@ -2734,8 +2904,10 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */ switch (new->link.type) { case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_IP6TNL: case NM_LINK_TYPE_INFINIBAND: case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_SIT: case NM_LINK_TYPE_VLAN: case NM_LINK_TYPE_VXLAN: delayed_action_schedule (platform, @@ -4034,6 +4206,224 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static int +link_gre_add (NMPlatform *platform, + const char *name, + NMPlatformLnkGre *props, + NMPlatformLink *out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "gre", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); + NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + +static int +link_ip6tnl_add (NMPlatform *platform, + const char *name, + NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + guint32 flowinfo; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + + if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local); + if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); + + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + +static int +link_ipip_add (NMPlatform *platform, + const char *name, + NMPlatformLnkIpIp *props, + NMPlatformLink *out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ipip", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + +static int +link_sit_add (NMPlatform *platform, + const char *name, + NMPlatformLnkSit *props, + NMPlatformLink *out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "sit", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static void _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, gboolean reset_all, @@ -5487,6 +5877,11 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->mesh_set_channel = mesh_set_channel; platform_class->mesh_set_ssid = mesh_set_ssid; + platform_class->link_gre_add = link_gre_add; + platform_class->link_ip6tnl_add = link_ip6tnl_add; + platform_class->link_ipip_add = link_ipip_add; + platform_class->link_sit_add = link_sit_add; + platform_class->ip4_address_get = ip4_address_get; platform_class->ip6_address_get = ip6_address_get; platform_class->ip4_address_get_all = ip4_address_get_all; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index bb82ab0959..959f6dfae3 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -71,6 +71,8 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF } \ } G_STMT_END +#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" + /*****************************************************************************/ #define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate)) @@ -1427,12 +1429,30 @@ nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlat return _link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link); } +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link); +} + +const NMPlatformLnkIpIp * +nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IPIP, out_link); +} + const NMPlatformLnkMacvlan * nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link); } +const NMPlatformLnkSit * +nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link); +} + const NMPlatformLnkVlan * nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -1709,6 +1729,45 @@ nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1); } +/** + * nm_platform_link_gre_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create a software GRE device. + */ +NMPlatformError +nm_platform_link_gre_add (NMPlatform *self, + const char *name, + NMPlatformLnkGre *props, + NMPlatformLink *out_link) +{ + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_GRE, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "gre", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_gre_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link) { @@ -1806,6 +1865,123 @@ nm_platform_infiniband_get_properties (NMPlatform *self, return TRUE; } +/** + * nm_platform_ip6tnl_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPv6 tunnel. + */ +NMPlatformError +nm_platform_link_ip6tnl_add (NMPlatform *self, + const char *name, + NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link) +{ + NMPlatformError plerr; + char buffer[INET6_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + if (!klass->link_ip6tnl_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** + * nm_platform_ipip_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPIP tunnel. + */ +NMPlatformError +nm_platform_link_ipip_add (NMPlatform *self, + const char *name, + NMPlatformLnkIpIp *props, + NMPlatformLink *out_link) +{ + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IPIP, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ipip", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_ipip_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** + * nm_platform_sit_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create a software SIT device. + */ +NMPlatformError +nm_platform_link_sit_add (NMPlatform *self, + const char *name, + NMPlatformLnkSit *props, + NMPlatformLink *out_link) +{ + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_SIT, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "sit", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_sit_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex) { @@ -2806,6 +2982,77 @@ nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char * } const char * +nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tclass[30]; + char str_flow[30]; + char str_encap[30]; + char str_proto[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "ip6tnl" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tclass */ + "%s" /* encap limit */ + "%s" /* flow label */ + "%s" /* proto */ + "", + nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), + nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), + nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit), + nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label), + nm_sprintf_buf (str_proto, " proto %u", lnk->proto)); + return buf; +} + +const char * +nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "ipip" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* path_mtu_discovery */ + "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", + lnk->path_mtu_discovery ? "" : " nopmtudisc"); + return buf; +} + +const char * nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len) { if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) @@ -2820,6 +3067,44 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g } const char * +nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_flags[30]; + char str_proto[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "sit" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* path_mtu_discovery */ + "%s" /* flags */ + "%s" /* proto */ + "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", + lnk->path_mtu_discovery ? "" : " nopmtudisc", + lnk->flags ? nm_sprintf_buf (str_flags, " flags 0x%x", lnk->flags) : "", + lnk->proto ? nm_sprintf_buf (str_proto, " proto 0x%x", lnk->proto) : ""); + return buf; +} + +const char * nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) { char *b; @@ -3361,6 +3646,34 @@ nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatfo } int +nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD_MEMCMP (a, b, local); + _CMP_FIELD_MEMCMP (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tclass); + _CMP_FIELD (a, b, encap_limit); + _CMP_FIELD (a, b, flow_label); + _CMP_FIELD (a, b, proto); + return 0; +} + +int +nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, local); + _CMP_FIELD (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tos); + _CMP_FIELD_BOOL (a, b, path_mtu_discovery); + return 0; +} + +int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b) { _CMP_SELF (a, b); @@ -3370,6 +3683,21 @@ nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkM } int +nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, local); + _CMP_FIELD (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tos); + _CMP_FIELD_BOOL (a, b, path_mtu_discovery); + _CMP_FIELD (a, b, flags); + _CMP_FIELD (a, b, proto); + return 0; +} + +int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b) { _CMP_SELF (a, b); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 00029b3aeb..5eb042cf78 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -63,6 +63,9 @@ typedef struct _NMPlatform NMPlatform; #define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ +/* Redefine this in host's endianness */ +#define NM_GRE_KEY 0x2000 + typedef enum { /*< skip >*/ /* dummy value, to enforce that the enum type is signed and has a size @@ -376,11 +379,42 @@ typedef struct { } NMPlatformLnkInfiniband; typedef struct { + int parent_ifindex; + struct in6_addr local; + struct in6_addr remote; + guint8 ttl; + guint8 tclass; + guint8 encap_limit; + guint flow_label; + guint8 proto; +} NMPlatformLnkIp6Tnl; + +typedef struct { + int parent_ifindex; + in_addr_t local; + in_addr_t remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; +} NMPlatformLnkIpIp; + +typedef struct { const char *mode; gboolean no_promisc; } NMPlatformLnkMacvlan; typedef struct { + int parent_ifindex; + in_addr_t local; + in_addr_t remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; + guint16 flags; + guint8 proto; +} NMPlatformLnkSit; + +typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; NMVlanFlags flags; @@ -524,6 +558,15 @@ typedef struct { const NMVlanQosMapping *egress_map, gsize n_egress_map); + gboolean (*link_gre_add) (NMPlatform *, const char *name, NMPlatformLnkGre *props, + NMPlatformLink *out_link); + gboolean (*link_ip6tnl_add) (NMPlatform *, const char *name, NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link); + gboolean (*link_ipip_add) (NMPlatform *, const char *name, NMPlatformLnkIpIp *props, + NMPlatformLink *out_link); + gboolean (*link_sit_add) (NMPlatform *, const char *name, NMPlatformLnkSit *props, + NMPlatformLink *out_link); + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link); gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi, @@ -712,8 +755,12 @@ char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *o const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -762,6 +809,16 @@ void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *a const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); + +NMPlatformError nm_platform_link_gre_add (NMPlatform *self, const char *name, NMPlatformLnkGre *props, + NMPlatformLink *out_link); +NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name, NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link); +NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, NMPlatformLnkIpIp *props, + NMPlatformLink *out_link); +NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, NMPlatformLnkSit *props, + NMPlatformLink *out_link); + const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen); GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex); GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex); @@ -803,7 +860,10 @@ gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6 const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); +const char *nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len); +const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len); const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -820,7 +880,10 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name, int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); +int nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b); +int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b); int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); +int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index ef467f4241..cb605c28f4 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -2045,6 +2045,24 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp, }, + [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6tnl", + .lnk_link_type = NM_LINK_TYPE_IP6TNL, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, + [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_IPIP, + .sizeof_data = sizeof (NMPObjectLnkIpIp), + .sizeof_public = sizeof (NMPlatformLnkIpIp), + .obj_type_name = "ipip", + .lnk_link_type = NM_LINK_TYPE_IPIP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ipip_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp, + }, [NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = { .obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN, .sizeof_data = sizeof (NMPObjectLnkMacvlan), @@ -2054,6 +2072,15 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp, }, + [NMP_OBJECT_TYPE_LNK_SIT - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_SIT, + .sizeof_data = sizeof (NMPObjectLnkSit), + .sizeof_public = sizeof (NMPlatformLnkSit), + .obj_type_name = "sit", + .lnk_link_type = NM_LINK_TYPE_SIT, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_sit_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, + }, [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { .obj_type = NMP_OBJECT_TYPE_LNK_VLAN, .sizeof_data = sizeof (NMPObjectLnkVlan), diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 971bd37eca..38224acd30 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -170,10 +170,22 @@ typedef struct { } NMPObjectLnkInfiniband; typedef struct { + NMPlatformLnkIp6Tnl _public; +} NMPObjectLnkIp6Tnl; + +typedef struct { + NMPlatformLnkIpIp _public; +} NMPObjectLnkIpIp; + +typedef struct { NMPlatformLnkMacvlan _public; } NMPObjectLnkMacvlan; typedef struct { + NMPlatformLnkSit _public; +} NMPObjectLnkSit; + +typedef struct { NMPlatformLnkVlan _public; guint n_ingress_qos_map; @@ -218,9 +230,18 @@ struct _NMPObject { NMPlatformLnkInfiniband lnk_infiniband; NMPObjectLnkInfiniband _lnk_infiniband; + NMPlatformLnkIpIp lnk_ipip; + NMPObjectLnkIpIp _lnk_ipip; + + NMPlatformLnkIp6Tnl lnk_ip6tnl; + NMPObjectLnkIp6Tnl _lnk_ip6tnl; + NMPlatformLnkMacvlan lnk_macvlan; NMPObjectLnkMacvlan _lnk_macvlan; + NMPlatformLnkSit lnk_sit; + NMPObjectLnkSit _lnk_sit; + NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 6f46546c46..595096d2fb 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -670,6 +670,140 @@ _ip_address_add (gboolean external_command, } while (TRUE); } +gboolean +nmtstp_link_gre_add (gboolean external_command, const char *name, NMPlatformLnkGre *lnk) +{ + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + success = !nmtstp_run_command ("ip tunnel add %s mode gre %s local %s remote %s ttl %u tos %02x %s", + name, + dev ? dev : "", + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_GRE, 100); + } else + success = nm_platform_link_gre_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS; + + return success; +} + +gboolean +nmtstp_link_ip6tnl_add (gboolean external_command, const char *name, NMPlatformLnkIp6Tnl *lnk) +{ + gboolean success; + char buffer[INET6_ADDRSTRLEN]; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + const char *mode; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + switch (lnk->proto) { + case IPPROTO_IPIP: + mode = "ipip6"; + break; + case IPPROTO_IPV6: + mode = "ip6ip6"; + break; + default: + g_assert (FALSE); + } + + success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %02x encaplimit %u flowlabel %x", + name, + mode, + dev, + nm_utils_inet6_ntop (&lnk->local, NULL), + nm_utils_inet6_ntop (&lnk->remote, buffer), + lnk->ttl, + lnk->tclass, + lnk->encap_limit, + lnk->flow_label); + if (success) + nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IP6TNL, 100); + } else + success = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS; + + return success; +} + +gboolean +nmtstp_link_ipip_add (gboolean external_command, const char *name, NMPlatformLnkIpIp *lnk) +{ + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + success = !nmtstp_run_command ("ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s", + name, + dev, + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IPIP, 100); + } else + success = nm_platform_link_ipip_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS; + + return success; +} + +gboolean +nmtstp_link_sit_add (gboolean external_command, const char *name, NMPlatformLnkSit *lnk) +{ + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + success = !nmtstp_run_command ("ip tunnel add %s mode sit %s local %s remote %s ttl %u tos %02x %s", + name, + dev, + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_SIT, 100); + } else + success = nm_platform_link_sit_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS; + + return success; +} + void nmtstp_ip4_address_add (gboolean external_command, int ifindex, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index ed7dd67fa1..6140f26406 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -135,6 +135,19 @@ void nmtstp_link_set_updown (gboolean external_command, int ifindex, gboolean up); +gboolean nmtstp_link_gre_add (gboolean external_command, + const char *name, + NMPlatformLnkGre *lnk); +gboolean nmtstp_link_ip6tnl_add (gboolean external_command, + const char *name, + NMPlatformLnkIp6Tnl *lnk); +gboolean nmtstp_link_ipip_add (gboolean external_command, + const char *name, + NMPlatformLnkIpIp *lnk); +gboolean nmtstp_link_sit_add (gboolean external_command, + const char *name, + NMPlatformLnkSit *lnk); + void init_tests (int *argc, char ***argv); void setup_tests (void); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 8a29df2d15..047dfe1cf7 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -659,32 +659,93 @@ test_software_detect (gconstpointer user_data) const NMPlatformLink *plink; const NMPObject *lnk; guint i_step; - int exit_code; + const gint EX = -1; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; switch (test_data->link_type) { case NM_LINK_TYPE_GRE: { + NMPlatformLnkGre lnk_gre = { }; gboolean gracefully_skip = FALSE; + inet_pton (AF_INET, "192.168.233.204", &lnk_gre.local); + inet_pton (AF_INET, "172.168.10.25", &lnk_gre.remote); + lnk_gre.parent_ifindex = ifindex_parent; + lnk_gre.ttl = 174; + lnk_gre.tos = 37; + lnk_gre.path_mtu_discovery = TRUE; + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gre0")) { /* Seems that the ip_gre module is not loaded... try to load it. */ gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0; } - exit_code = nmtstp_run_command ("ip tunnel add %s mode gre remote 172.168.10.25 local 192.168.233.204 ttl 174", DEVICE_NAME); - if (exit_code != 0) { + + if (!nmtstp_link_gre_add (EX, DEVICE_NAME, &lnk_gre)) { if (gracefully_skip) { g_test_skip ("Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)"); goto out_delete_parent; } - g_error ("Failed adding GRE tunnel: exit code %d", exit_code); + g_error ("Failed adding GRE tunnel"); } break; } + case NM_LINK_TYPE_IPIP: { + NMPlatformLnkIpIp lnk_ipip = { }; + + inet_pton (AF_INET, "1.2.3.4", &lnk_ipip.local); + inet_pton (AF_INET, "5.6.7.8", &lnk_ipip.remote); + lnk_ipip.parent_ifindex = ifindex_parent; + lnk_ipip.tos = 32; + lnk_ipip.path_mtu_discovery = FALSE; + + if (!nmtstp_link_ipip_add (EX, DEVICE_NAME, &lnk_ipip)) + g_error ("Failed adding IPIP tunnel"); + break; + } + case NM_LINK_TYPE_IP6TNL: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + + inet_pton (AF_INET6, "fd01::15", &lnk_ip6tnl.local); + inet_pton (AF_INET6, "fd01::16", &lnk_ip6tnl.remote); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 20; + lnk_ip6tnl.encap_limit = 6; + lnk_ip6tnl.flow_label = 1337; + lnk_ip6tnl.proto = IPPROTO_IPV6; + + if (!nmtstp_link_ip6tnl_add (EX, DEVICE_NAME, &lnk_ip6tnl)) + g_error ("Failed adding IPv6 tunnel"); + break; + } case NM_LINK_TYPE_MACVLAN: nmtstp_run_command_check ("ip link add name %s link %s type macvlan", DEVICE_NAME, PARENT_NAME); break; + case NM_LINK_TYPE_SIT: { + NMPlatformLnkSit lnk_sit = { }; + gboolean gracefully_skip = FALSE; + + inet_pton (AF_INET, "192.168.200.1", &lnk_sit.local); + inet_pton (AF_INET, "172.25.100.14", &lnk_sit.remote); + lnk_sit.parent_ifindex = ifindex_parent; + lnk_sit.ttl = 0; + lnk_sit.tos = 31; + lnk_sit.path_mtu_discovery = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "sit0")) { + /* Seems that the sit module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "sit", NULL) != 0; + } + + if (!nmtstp_link_sit_add (EX, DEVICE_NAME, &lnk_sit)) { + if (gracefully_skip) { + g_test_skip ("Cannot create sit tunnel because of missing sit module (modprobe sit)"); + goto out_delete_parent; + } + g_error ("Failed adding SIT tunnel"); + } + break; + } case NM_LINK_TYPE_VLAN: nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME); break; @@ -741,7 +802,7 @@ test_software_detect (gconstpointer user_data) const NMPlatformLnkGre *plnk = &lnk->lnk_gre; g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, 0); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); g_assert_cmpint (plnk->input_flags, ==, 0); g_assert_cmpint (plnk->output_flags, ==, 0); g_assert_cmpint (plnk->input_key, ==, 0); @@ -749,10 +810,36 @@ test_software_detect (gconstpointer user_data) nmtst_assert_ip4_address (plnk->local, "192.168.233.204"); nmtst_assert_ip4_address (plnk->remote, "172.168.10.25"); g_assert_cmpint (plnk->ttl, ==, 174); - g_assert_cmpint (plnk->tos, ==, 0); + g_assert_cmpint (plnk->tos, ==, 37); g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE); break; } + case NM_LINK_TYPE_IP6TNL: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::15"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tclass, ==, 20); + g_assert_cmpint (plnk->encap_limit, ==, 6); + g_assert_cmpint (plnk->flow_label, ==, 1337); + g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); + break; + } + case NM_LINK_TYPE_IPIP: { + const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip; + + g_assert (plnk == nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip4_address (plnk->local, "1.2.3.4"); + nmtst_assert_ip4_address (plnk->remote, "5.6.7.8"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tos, ==, 32); + g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); + break; + } case NM_LINK_TYPE_MACVLAN: { const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan; @@ -761,6 +848,18 @@ test_software_detect (gconstpointer user_data) g_assert_cmpstr (plnk->mode, ==, "vepa"); break; } + case NM_LINK_TYPE_SIT: { + const NMPlatformLnkSit *plnk = &lnk->lnk_sit; + + g_assert (plnk == nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip4_address (plnk->local, "192.168.200.1"); + nmtst_assert_ip4_address (plnk->remote, "172.25.100.14"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tos, ==, 31); + g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); + break; + } case NM_LINK_TYPE_VLAN: { const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; @@ -1579,7 +1678,10 @@ setup_tests (void) g_test_add_func ("/link/external", test_external); test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); + test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0); + test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); + test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 219e0270ba..18fce10088 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -150,7 +150,7 @@ TESTS = \ if ENABLE_TESTS check-local: - @for t in bond bridge ethernet gre infiniband macvlan tun veth vlan vxlan; do \ + @for t in bond bridge ethernet infiniband ip_tunnel macvlan tun veth vlan vxlan; do \ # Ensure the device subclass factory registration constructors exist \ # which could inadvertently break if src/Makefile.am gets changed \ if ! LC_ALL=C nm $(top_builddir)/src/NetworkManager | LC_ALL=C grep -q "register_device_factory_internal_$$t" ; then \ |