components/openvswitch/files/lib/netdev-solaris.c
changeset 5730 cca4aa297e68
parent 5090 5f131162e136
child 6018 b5072b523988
equal deleted inserted replaced
5729:ad3057df09ab 5730:cca4aa297e68
     1 /*
     1 /*
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
     3  */
     3  */
     4 
     4 
     5 /*
     5 /*
     6  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
     6  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
     7  *
     7  *
    63 #include "unaligned.h"
    63 #include "unaligned.h"
    64 #include "vlog.h"
    64 #include "vlog.h"
    65 
    65 
    66 #include "netdev-solaris.h"
    66 #include "netdev-solaris.h"
    67 #include "util-solaris.h"
    67 #include "util-solaris.h"
       
    68 #include "dpif-solaris.h"
    68 
    69 
    69 /*
    70 /*
    70  * Enable vlog() for this module
    71  * Enable vlog() for this module
    71  */
    72  */
    72 VLOG_DEFINE_THIS_MODULE(netdev_solaris);
    73 VLOG_DEFINE_THIS_MODULE(netdev_solaris);
   122 	VALID_LINKCLASS		= 1 << 5,
   123 	VALID_LINKCLASS		= 1 << 5,
   123 	VALID_FEATURES		= 1 << 6
   124 	VALID_FEATURES		= 1 << 6
   124 };
   125 };
   125 
   126 
   126 /*
   127 /*
   127  * When network devices are constructed, the internal devices (i.e., bridges)
       
   128  * are initially created over this etherstub and are moved when uplink ports
       
   129  * are added to the bridge.
       
   130  */
       
   131 #define	NETDEV_IMPL_ETHERSTUB	"ovs.etherstub0"
       
   132 
       
   133 /*
       
   134  * Used to track state of IP plumbing on network devices.
   128  * Used to track state of IP plumbing on network devices.
   135  */
   129  */
   136 #define	SOLARIS_IPV4 0x01
   130 #define	SOLARIS_IPV4 0x01
   137 #define	SOLARIS_IPV6 0x02
   131 #define	SOLARIS_IPV6 0x02
   138 
   132 
   150 static boolean_t	kstat2_handle_initialized = B_FALSE;
   144 static boolean_t	kstat2_handle_initialized = B_FALSE;
   151 static struct ovs_mutex	kstat_mutex = OVS_MUTEX_INITIALIZER;
   145 static struct ovs_mutex	kstat_mutex = OVS_MUTEX_INITIALIZER;
   152 
   146 
   153 static int netdev_solaris_init(void);
   147 static int netdev_solaris_init(void);
   154 static struct netdev_solaris *netdev_solaris_cast(const struct netdev *);
   148 static struct netdev_solaris *netdev_solaris_cast(const struct netdev *);
       
   149 
       
   150 /* Maintaining a mapping of every netdev->name to its bridge name. */
       
   151 struct shash port_to_bridge_map = SHASH_INITIALIZER(&port_to_bridge_map);
   155 
   152 
   156 /*
   153 /*
   157  * An instance of a traffic control class.
   154  * An instance of a traffic control class.
   158  *
   155  *
   159  * Always associated with a particular network device.
   156  * Always associated with a particular network device.
   463 	ovs_assert(is_netdev_solaris_class(netdev_get_class(netdev)));
   460 	ovs_assert(is_netdev_solaris_class(netdev_get_class(netdev)));
   464 
   461 
   465 	return (CONTAINER_OF(netdev, struct netdev_solaris, up));
   462 	return (CONTAINER_OF(netdev, struct netdev_solaris, up));
   466 }
   463 }
   467 
   464 
       
   465 char *
       
   466 netdev_solaris_get_class(struct netdev *netdev)
       
   467 {
       
   468 	return ((netdev_solaris_cast(netdev))->class);
       
   469 }
       
   470 
   468 static int
   471 static int
   469 netdev_solaris_plumb(const struct netdev *netdev_, sa_family_t af)
   472 netdev_solaris_plumb(const struct netdev *netdev_, sa_family_t af)
   470 {
   473 {
   471 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   474 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   472 	const char		*netdev_name = netdev_get_name(netdev_);
   475 	const char		*netdev_name = netdev_get_name(netdev_);
   522 		sock = sock6;
   525 		sock = sock6;
   523 		astring = "IPv6";
   526 		astring = "IPv6";
   524 		proto = SOLARIS_IPV6;
   527 		proto = SOLARIS_IPV6;
   525 	}
   528 	}
   526 
   529 
   527 	if ((netdev->implicitly_plumbed & proto) == 0)
   530 	if ((netdev->implicitly_plumbed & proto) == 0 &&
       
   531 	    (netdev->up.netdev_class != &netdev_internal_class)) {
   528 		return (0);
   532 		return (0);
       
   533 	}
   529 
   534 
   530 	error = solaris_unplumb_if(sock, netdev_name, af);
   535 	error = solaris_unplumb_if(sock, netdev_name, af);
   531 	if (error != 0) {
   536 	if (error != 0) {
   532 		VLOG_ERR("%s device could not be unplumbed", netdev_name);
   537 		if (error == ENXIO &&
   533 		return (error);
   538 		    netdev->up.netdev_class == &netdev_internal_class) {
       
   539 			return (0);
       
   540 		}
       
   541 		VLOG_ERR("%s device could not be unplumbed %d", netdev_name,
       
   542 		    error);
   534 	}
   543 	}
   535 	VLOG_ERR("%s device unplumbed for %s", netdev_name, astring);
   544 	VLOG_ERR("%s device unplumbed for %s", netdev_name, astring);
   536 	netdev->implicitly_plumbed &= ~proto;
   545 	netdev->implicitly_plumbed &= ~proto;
   537 	netdev->plumbed &= ~proto;
   546 	netdev->plumbed &= ~proto;
   538 
   547 
   705 	struct netdev_solaris *netdev = xzalloc(sizeof (*netdev));
   714 	struct netdev_solaris *netdev = xzalloc(sizeof (*netdev));
   706 
   715 
   707 	return (&netdev->up);
   716 	return (&netdev->up);
   708 }
   717 }
   709 
   718 
       
   719 static void
       
   720 netdev_solaris_add_port_to_bridge_mapping(const struct netdev
       
   721 		*netdev, const char *brname)
       
   722 {
       
   723 	VLOG_DBG("netdev_solaris_add_port_to_bridge_mapping: adding a mapping "
       
   724 	    "<%s,%s> to port_to_bridge_map", netdev->name, brname);
       
   725 	shash_add_nocopy(&port_to_bridge_map, netdev->name, brname);
       
   726 }
       
   727 
   710 static int
   728 static int
   711 netdev_solaris_unconfigure_uplink(const struct netdev *netdev_)
   729 netdev_solaris_unconfigure_uplink(const struct netdev *netdev_)
   712 {
   730 {
   713 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   731 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   714 	const char		*netdev_name = netdev_get_name(netdev_);
   732 	const char		*netdev_name = netdev_get_name(netdev_);
   715 	int			error;
   733 	int			error;
       
   734 	char			curr_lower[DLADM_PROP_VAL_MAX];
       
   735 	struct netdev		*netdev_to_migrate = NULL;
       
   736 	char			*new_lower = NULL;
       
   737 	bool			b_error = false;
   716 
   738 
   717 	VLOG_DBG("netdev_solaris_unconfigure_uplink device %s", netdev_name);
   739 	VLOG_DBG("netdev_solaris_unconfigure_uplink device %s", netdev_name);
   718 
   740 
   719 	error = solaris_modify_vnic(NETDEV_IMPL_ETHERSTUB, netdev->brname);
   741 	error = solaris_get_dlprop(netdev->brname, "lower-link", "current",
   720 	if (error != 0 && error != ENODEV) {
   742 	    curr_lower, sizeof (curr_lower));
   721 		VLOG_ERR("failed to unconfigure %s as uplink for %s: "
   743 	if (error) {
   722 		    "%s", netdev_name, netdev->brname,
   744 		VLOG_ERR("netdev_solaris_unconfigure_uplink couldn't obtain "
   723 		    ovs_strerror(error));
   745 		    "bridge(%s) lowerlink", netdev->brname);
       
   746 		return (0);
       
   747 	}
       
   748 
       
   749 	if (strcmp(netdev_name, curr_lower) == 0) {
       
   750 		/*
       
   751 		 * The uplink which we are trying to remove has bridge vnic on
       
   752 		 * top of it. We need to migrate bridge vnic to a different
       
   753 		 * uplink or to ovs.etherstub0 if uplink_port_list is empty.
       
   754 		 */
       
   755 		VLOG_DBG("netdev_solaris_unconfigure_uplink: unconfiguring the "
       
   756 		    "uplink (%s) which is the bridge %s's lowerlink (%s)",
       
   757 		    netdev_name, netdev->brname, curr_lower);
       
   758 
       
   759 		netdev_to_migrate = dpif_solaris_obtain_netdev_to_migrate(
       
   760 		    netdev->brname, &b_error);
       
   761 		if (b_error) {
       
   762 			VLOG_ERR("netdev_solaris_unconfigure_uplink: couldn't "
       
   763 			    "obtain netdev_to_migrate for bridge vnic %s",
       
   764 			    netdev->brname);
       
   765 			return (0);
       
   766 		}
       
   767 
       
   768 		if (netdev_to_migrate == NULL)
       
   769 			new_lower = NETDEV_IMPL_ETHERSTUB;
       
   770 		else
       
   771 			new_lower = netdev_to_migrate->name;
       
   772 
       
   773 		VLOG_DBG("netdev_solaris_unconfigure_uplink migrating bridge "
       
   774 		    "vnic to %s", new_lower);
       
   775 
       
   776 		error = solaris_modify_vnic(new_lower, netdev->brname);
       
   777 		if (error != 0) {
       
   778 			VLOG_ERR("failed to unconfigure %s as uplink for %s: "
       
   779 			    "%s", netdev_name, netdev->brname,
       
   780 			    ovs_strerror(error));
       
   781 			return (0);
       
   782 		}
       
   783 
       
   784 		/*
       
   785 		 * reset internal port's physname and refresh its port channel.
       
   786 		 */
       
   787 		dpif_solaris_migrate_internal_port(netdev->brname, new_lower);
   724 	}
   788 	}
   725 	return (0);
   789 	return (0);
   726 }
   790 }
   727 
   791 
   728 static int
   792 static int
   729 netdev_solaris_configure_uplink(const struct netdev *netdev_,
   793 netdev_solaris_configure_uplink(const struct netdev *netdev_,
   730     const char *brname)
   794     const char *brname)
   731 {
   795 {
   732 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   796 	struct netdev_solaris	*netdev = netdev_solaris_cast(netdev_);
   733 	const char		*netdev_name = netdev_get_name(netdev_);
   797 	const char		*new_uplink = netdev_get_name(netdev_);
   734 	char			buffer[DLADM_PROP_VAL_MAX];
   798 	char			curr_lower[DLADM_PROP_VAL_MAX];
   735 	int			error;
   799 	int			error;
   736 
   800 	const char		*netdev_existing_class;
   737 	VLOG_DBG("netdev_solaris_configure_uplink device %s", netdev_name);
   801 	struct netdev		*i_netdev;
       
   802 	boolean_t		migrated = B_FALSE;
       
   803 
       
   804 	VLOG_DBG("netdev_solaris_configure_uplink device %s", new_uplink);
   738 
   805 
   739 	/*
   806 	/*
   740 	 * Normally, we would expect to see that the bridge VNIC has already
   807 	 * Normally, we would expect to see that the bridge VNIC has already
   741 	 * been created by a call to netdev_solaris_construct() to create the
   808 	 * been created by a call to netdev_solaris_construct() to create the
   742 	 * bridge netdev. However, on a service restart ovs-vswitchd sometimes
   809 	 * bridge netdev. However, on a service restart ovs-vswitchd sometimes
   743 	 * adds the lower-link port prior to adding the bridge's internal port.
   810 	 * adds the lower-link port prior to adding the bridge's internal port.
   744 	 * As a result, we need to create the bridge VNIC here if it does not
   811 	 * As a result, we need to create the bridge VNIC here if it does not
   745 	 * already exist.
   812 	 * already exist.
   746 	 */
   813 	 */
   747 	error = solaris_get_dlprop(brname, "lower-link", "current",
   814 	error = solaris_get_dlprop(brname, "lower-link", "current",
   748 	    buffer, sizeof (buffer));
   815 	    curr_lower, sizeof (curr_lower));
       
   816 	VLOG_DBG("netdev_solaris_configure_uplink lower-link:%s", curr_lower);
       
   817 
   749 	if (error == ENODEV) {
   818 	if (error == ENODEV) {
   750 		VLOG_DBG("%s vnic being created on %s",
   819 		/*
   751 		    brname, netdev_name);
   820 		 * No implicit VNIC being created yet, create it now
   752 		error = solaris_create_vnic(netdev_name, brname);
   821 		 */
   753 		if (error != 0) {
   822 		VLOG_DBG("%s vnic being created on %s", brname, new_uplink);
       
   823 		error = solaris_create_vnic(new_uplink, brname);
       
   824 		if (error == 0) {
       
   825 			(void) strlcpy(netdev->brname, brname,
       
   826 			    sizeof (netdev->brname));
       
   827 		} else {
   754 			VLOG_ERR("Failed to create vnic for %s: %s",
   828 			VLOG_ERR("Failed to create vnic for %s: %s",
   755 			    brname, ovs_strerror(error));
   829 			    brname, ovs_strerror(error));
   756 		}
   830 		}
   757 		goto exit;
   831 		goto exit;
   758 	} else if (error != 0) {
   832 	} else if (error != 0) {
   763 
   837 
   764 	/*
   838 	/*
   765 	 * If the lower-link is already set correctly, then return with
   839 	 * If the lower-link is already set correctly, then return with
   766 	 * success.
   840 	 * success.
   767 	 */
   841 	 */
   768 	if (strcmp(buffer, netdev_name) == 0) {
   842 	if (strcmp(curr_lower, new_uplink) == 0) {
       
   843 		VLOG_DBG("netdev_solaris_configure_uplink lower-link(%s) is "
       
   844 		    "already correctly set. (%s)", curr_lower, new_uplink);
   769 		error = 0;
   845 		error = 0;
   770 		goto exit;
   846 		goto exit;
   771 	}
   847 	}
   772 
   848 
   773 	/*
   849 	if (strcmp(curr_lower, NETDEV_IMPL_ETHERSTUB) == 0) {
   774 	 * If the lower-link is already set to something other than the
   850 		/*
   775 	 * etherstub, something is wrong.
   851 		 * Bridge vnic is on ovs.etherstub0. We have to migrate the
   776 	 */
   852 		 * bridge vnic to the uplink
   777 	if (strcmp(buffer, NETDEV_IMPL_ETHERSTUB) != 0) {
   853 		 */
   778 		VLOG_ERR("Bridge already has uplink %s", buffer);
   854 		VLOG_DBG("bridge vnic %s is on %s, migrating it to %s",
   779 		error = EEXIST;
   855 		    brname, curr_lower, new_uplink);
   780 		goto exit;
   856 
   781 	}
   857 		error = solaris_modify_vnic(new_uplink, brname);
   782 
   858 		if (error != 0) {
   783 	/*
   859 			VLOG_ERR("failed to configure %s as uplink: %s",
   784 	 * This is the "normal" case, where the bridge VNIC existed and had
   860 			    new_uplink, ovs_strerror(error));
   785 	 * the etherstub as its lower-link. Move the VNIC to its uplink.
   861 			goto exit;
   786 	 */
   862 		}
   787 	error = solaris_modify_vnic(netdev_name, brname);
   863 		migrated = B_TRUE;
   788 	if (error != 0) {
   864 	} else {
   789 		VLOG_ERR("failed to configure %s as uplink: %s",
   865 		/*
   790 		    netdev_name, ovs_strerror(error));
   866 		 * Bridge vnic is already on an uplink. Now we see if the
   791 		goto exit;
   867 		 * uplink to be added is other than etherstub or not.
       
   868 		 * If the bridge vnic is currently residing on an etherstub
       
   869 		 * and the one to be configured is not etherstub,
       
   870 		 * then we migrate the bridge vnic.
       
   871 		 */
       
   872 		i_netdev = netdev_from_name(curr_lower);
       
   873 		if (!i_netdev) {
       
   874 			VLOG_ERR("netdev_solaris_configure_uplink error "
       
   875 			    "in fetching lower-link netdev for %s", curr_lower);
       
   876 			goto exit;
       
   877 		}
       
   878 		/* i_netdev->ref_cnt--; */
       
   879 		netdev_close(i_netdev);
       
   880 
       
   881 		netdev_existing_class = netdev_solaris_get_class(i_netdev);
       
   882 		if ((strcmp(netdev_existing_class, "etherstub") == 0) &&
       
   883 		    (strcmp(netdev->class, "etherstub") != 0)) {
       
   884 			error = solaris_modify_vnic(new_uplink, brname);
       
   885 			if (error != 0) {
       
   886 				VLOG_ERR("failed to configure %s as uplink: %s",
       
   887 				    new_uplink, ovs_strerror(error));
       
   888 				goto exit;
       
   889 			}
       
   890 			migrated = B_TRUE;
       
   891 		}
   792 	}
   892 	}
   793 	(void) strlcpy(netdev->brname, brname, sizeof (netdev->brname));
   893 	(void) strlcpy(netdev->brname, brname, sizeof (netdev->brname));
   794 
   894 
   795 exit:
   895 exit:
       
   896 	/*
       
   897 	 * reset internal port's physname and refresh its port channel.
       
   898 	 */
       
   899 	if (migrated)
       
   900 		dpif_solaris_migrate_internal_port(brname, new_uplink);
   796 	return (error);
   901 	return (error);
   797 }
   902 }
   798 
   903 
   799 static boolean_t
   904 static boolean_t
   800 solaris_is_if_plumbed(struct netdev *netdev_, sa_family_t af, uint64_t *flags)
   905 solaris_is_if_plumbed(struct netdev *netdev_, sa_family_t af, uint64_t *flags)
  2337 	GET_STATUS,							\
  2442 	GET_STATUS,							\
  2338 	netdev_solaris_arp_lookup,					\
  2443 	netdev_solaris_arp_lookup,					\
  2339 	netdev_solaris_update_flags,					\
  2444 	netdev_solaris_update_flags,					\
  2340 	netdev_solaris_configure_uplink,				\
  2445 	netdev_solaris_configure_uplink,				\
  2341 	netdev_solaris_is_uplink,					\
  2446 	netdev_solaris_is_uplink,					\
       
  2447 	netdev_solaris_add_port_to_bridge_mapping,			\
  2342 	NULL,								\
  2448 	NULL,								\
  2343 	NULL,								\
  2449 	NULL,								\
  2344 	NULL,								\
  2450 	NULL,								\
  2345 	NULL,								\
  2451 	NULL,								\
  2346 	NULL,								\
  2452 	NULL,								\