X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev.c;h=481671f798e1c9d3a518ebed0df4babc62e0f49f;hb=refs%2Fheads%2Fxs5.7;hp=5752914789c710ddd0ca6d92fd4d24bf31e0b27a;hpb=8b61709d5ec6c4ef58a04fcaefde617ff63fa10d;p=sliver-openvswitch.git diff --git a/lib/netdev.c b/lib/netdev.c index 575291478..481671f79 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -43,7 +43,7 @@ static const struct netdev_class *netdev_classes[] = { &netdev_linux_class, &netdev_tap_class, }; -enum { N_NETDEV_CLASSES = ARRAY_SIZE(netdev_classes) }; +static int n_netdev_classes = ARRAY_SIZE(netdev_classes); /* All open network devices. */ static struct list netdev_list = LIST_INITIALIZER(&netdev_list); @@ -65,24 +65,29 @@ netdev_initialize(void) { static int status = -1; if (status < 0) { - int i; + int i, j; fatal_signal_add_hook(restore_all_flags, NULL, true); status = 0; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = j = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->init) { int retval = class->init(); - if (retval) { + if (!retval) { + netdev_classes[j++] = class; + } else { VLOG_ERR("failed to initialize %s network device " "class: %s", class->name, strerror(retval)); if (!status) { status = retval; } } + } else { + netdev_classes[j++] = class; } } + n_netdev_classes = j; } return status; } @@ -95,7 +100,7 @@ void netdev_run(void) { int i; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->run) { class->run(); @@ -111,7 +116,7 @@ void netdev_wait(void) { int i; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->wait) { class->wait(); @@ -136,11 +141,7 @@ netdev_open(const char *name_, int ethertype, struct netdev **netdevp) int error; int i; - error = netdev_initialize(); - if (error) { - return error; - } - + netdev_initialize(); colon = strchr(name, ':'); if (colon) { *colon = '\0'; @@ -151,7 +152,7 @@ netdev_open(const char *name_, int ethertype, struct netdev **netdevp) suffix = name; } - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (!strcmp(prefix, class->prefix)) { error = class->open(name_, suffix, ethertype, &netdev); @@ -162,6 +163,7 @@ netdev_open(const char *name_, int ethertype, struct netdev **netdevp) exit: *netdevp = error ? NULL : netdev; + free(name); return error; } @@ -220,13 +222,10 @@ netdev_enumerate(struct svec *svec) svec_init(svec); - error = netdev_initialize(); - if (error) { - return error; - } + netdev_initialize(); error = 0; - for (i = 0; i < N_NETDEV_CLASSES; i++) { + for (i = 0; i < n_netdev_classes; i++) { const struct netdev_class *class = netdev_classes[i]; if (class->enumerate) { int retval = class->enumerate(svec); @@ -395,9 +394,9 @@ netdev_set_advertisements(struct netdev *netdev, uint32_t advertise) : EOPNOTSUPP); } -/* If 'netdev' has an assigned IPv4 address, sets '*in4' to that address and - * returns 0. Otherwise, returns a positive errno value and sets '*in4' to 0 - * (INADDR_ANY). +/* If 'netdev' has an assigned IPv4 address, sets '*address' to that address + * and '*netmask' to its netmask and returns 0. Otherwise, returns a positive + * errno value and sets '*address' to 0 (INADDR_ANY). * * The following error values have well-defined meanings: * @@ -405,18 +404,24 @@ netdev_set_advertisements(struct netdev *netdev, uint32_t advertise) * * - EOPNOTSUPP: No IPv4 network stack attached to 'netdev'. * - * 'in4' may be null, in which case the address itself is not reported. */ + * 'address' or 'netmask' or both may be null, in which case the address or netmask + * is not reported. */ int -netdev_get_in4(const struct netdev *netdev, struct in_addr *in4) +netdev_get_in4(const struct netdev *netdev, + struct in_addr *address_, struct in_addr *netmask_) { - struct in_addr dummy; + struct in_addr address; + struct in_addr netmask; int error; error = (netdev->class->get_in4 - ? netdev->class->get_in4(netdev, in4 ? in4 : &dummy) + ? netdev->class->get_in4(netdev, &address, &netmask) : EOPNOTSUPP); - if (error && in4) { - in4->s_addr = 0; + if (address_) { + address_->s_addr = error ? 0 : address.s_addr; + } + if (netmask_) { + netmask_->s_addr = error ? 0 : netmask.s_addr; } return error; } @@ -443,6 +448,28 @@ netdev_add_router(struct netdev *netdev, struct in_addr router) : EOPNOTSUPP); } +/* Looks up the next hop for 'host' for the TCP/IP stack that corresponds to + * 'netdev'. If a route cannot not be determined, sets '*next_hop' to 0, + * '*netdev_name' to null, and returns a positive errno value. Otherwise, if a + * next hop is found, stores the next hop gateway's address (0 if 'host' is on + * a directly connected network) in '*next_hop' and a copy of the name of the + * device to reach 'host' in '*netdev_name', and returns 0. The caller is + * responsible for freeing '*netdev_name' (by calling free()). */ +int +netdev_get_next_hop(const struct netdev *netdev, + const struct in_addr *host, struct in_addr *next_hop, + char **netdev_name) +{ + int error = (netdev->class->get_next_hop + ? netdev->class->get_next_hop(host, next_hop, netdev_name) + : EOPNOTSUPP); + if (error) { + next_hop->s_addr = 0; + *netdev_name = NULL; + } + return error; +} + /* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address and * returns 0. Otherwise, returns a positive errno value and sets '*in6' to * all-zero-bits (in6addr_any). @@ -637,7 +664,7 @@ netdev_find_dev_by_in4(const struct in_addr *in4) struct in_addr dev_in4; if (!netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev) - && !netdev_get_in4(netdev, &dev_in4) + && !netdev_get_in4(netdev, &dev_in4, NULL) && dev_in4.s_addr == in4->s_addr) { goto exit; }