+ SMAP_FOR_EACH (node, args) {
+ if (!strcmp(node->key, "remote_ip")) {
+ struct in_addr in_addr;
+ if (lookup_ip(node->value, &in_addr)) {
+ VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
+ } else {
+ daddr = in_addr.s_addr;
+ }
+ } else if (!strcmp(node->key, "local_ip")) {
+ struct in_addr in_addr;
+ if (lookup_ip(node->value, &in_addr)) {
+ VLOG_WARN("%s: bad %s 'local_ip'", name, type);
+ } else {
+ saddr = in_addr.s_addr;
+ }
+ } else if (!strcmp(node->key, "tos")) {
+ if (!strcmp(node->value, "inherit")) {
+ flags |= TNL_F_TOS_INHERIT;
+ } else {
+ char *endptr;
+ int tos;
+ tos = strtol(node->value, &endptr, 0);
+ if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
+ nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TOS, tos);
+ } else {
+ VLOG_WARN("%s: invalid TOS %s", name, node->value);
+ }
+ }
+ } else if (!strcmp(node->key, "ttl")) {
+ if (!strcmp(node->value, "inherit")) {
+ flags |= TNL_F_TTL_INHERIT;
+ } else {
+ nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->value));
+ }
+ } else if (!strcmp(node->key, "csum") && is_gre) {
+ if (!strcmp(node->value, "true")) {
+ flags |= TNL_F_CSUM;
+ }
+ } else if (!strcmp(node->key, "df_inherit")) {
+ if (!strcmp(node->value, "true")) {
+ flags |= TNL_F_DF_INHERIT;
+ }
+ } else if (!strcmp(node->key, "df_default")) {
+ if (!strcmp(node->value, "false")) {
+ flags &= ~TNL_F_DF_DEFAULT;
+ }
+ } else if (!strcmp(node->key, "pmtud")) {
+ if (!strcmp(node->value, "true")) {
+ flags |= TNL_F_PMTUD;
+ }
+ } else if (!strcmp(node->key, "header_cache")) {
+ if (!strcmp(node->value, "false")) {
+ flags &= ~TNL_F_HDR_CACHE;
+ }
+ } else if (!strcmp(node->key, "peer_cert") && is_ipsec) {
+ if (smap_get(args, "certificate")) {
+ ipsec_mech_set = true;
+ } else {
+ const char *use_ssl_cert;
+
+ /* If the "use_ssl_cert" is true, then "certificate" and
+ * "private_key" will be pulled from the SSL table. The
+ * use of this option is strongly discouraged, since it
+ * will like be removed when multiple SSL configurations
+ * are supported by OVS.
+ */
+ use_ssl_cert = smap_get(args, "use_ssl_cert");
+ if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
+ VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
+ name);
+ return EINVAL;
+ }
+ ipsec_mech_set = true;
+ }
+ } else if (!strcmp(node->key, "psk") && is_ipsec) {
+ ipsec_mech_set = true;
+ } else if (is_ipsec
+ && (!strcmp(node->key, "certificate")
+ || !strcmp(node->key, "private_key")
+ || !strcmp(node->key, "use_ssl_cert"))) {
+ /* Ignore options not used by the netdev. */
+ } else if (!strcmp(node->key, "key") ||
+ !strcmp(node->key, "in_key") ||
+ !strcmp(node->key, "out_key")) {
+ /* Handled separately below. */
+ } else {
+ VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
+ }
+ }
+
+ if (is_ipsec) {
+ static pid_t pid = 0;
+ if (pid <= 0) {
+ char *file_name = xasprintf("%s/%s", ovs_rundir(),
+ "ovs-monitor-ipsec.pid");
+ pid = read_pidfile(file_name);
+ free(file_name);
+ }
+
+ if (pid < 0) {
+ VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
+ name);
+ return EINVAL;
+ }
+
+ if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
+ VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
+ return EINVAL;
+ }
+
+ if (!ipsec_mech_set) {
+ VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
+ name);
+ return EINVAL;
+ }
+ }
+
+ set_key(args, "in_key", OVS_TUNNEL_ATTR_IN_KEY, options);
+ set_key(args, "out_key", OVS_TUNNEL_ATTR_OUT_KEY, options);
+
+ if (!daddr) {
+ VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
+ name, type);
+ return EINVAL;
+ }
+ nl_msg_put_be32(options, OVS_TUNNEL_ATTR_DST_IPV4, daddr);
+
+ if (saddr) {
+ if (ip_is_multicast(daddr)) {
+ VLOG_WARN("%s: remote_ip is multicast, ignoring local_ip", name);
+ } else {
+ nl_msg_put_be32(options, OVS_TUNNEL_ATTR_SRC_IPV4, saddr);
+ }
+ }
+
+ nl_msg_put_u32(options, OVS_TUNNEL_ATTR_FLAGS, flags);