diff options
author | Ben Pfaff <blp@nicira.com> | 2009-12-02 11:49:53 -0800 |
---|---|---|
committer | Ben Pfaff <blp@nicira.com> | 2009-12-02 11:49:53 -0800 |
commit | 58fda1dab104041fc693032475ec4662c1a52849 (patch) | |
tree | c6adcb818ad9233155d4d65872e8144dae6fe723 /lib | |
parent | c3bb4bd7f1d9c045a5e5d7062b09d4dac4e48195 (diff) | |
parent | 6c88d577e83db12f73df12be8fc575419b011fda (diff) | |
download | openvswitch-58fda1dab104041fc693032475ec4662c1a52849.tar.gz |
Merge "master" branch into "db".
Diffstat (limited to 'lib')
-rw-r--r-- | lib/backtrace.c | 6 | ||||
-rw-r--r-- | lib/classifier.h | 14 | ||||
-rw-r--r-- | lib/dpif-linux.c | 2 | ||||
-rw-r--r-- | lib/dpif-netdev.c | 30 | ||||
-rw-r--r-- | lib/dpif-provider.h | 4 | ||||
-rw-r--r-- | lib/dpif.c | 24 | ||||
-rw-r--r-- | lib/dpif.h | 1 | ||||
-rw-r--r-- | lib/fault.c | 2 | ||||
-rw-r--r-- | lib/flow.c | 2 | ||||
-rw-r--r-- | lib/leak-checker.c | 2 | ||||
-rw-r--r-- | lib/learning-switch.c | 43 | ||||
-rw-r--r-- | lib/learning-switch.h | 4 | ||||
-rw-r--r-- | lib/lockfile.c | 4 | ||||
-rw-r--r-- | lib/mac-learning.c | 35 | ||||
-rw-r--r-- | lib/mac-learning.h | 3 | ||||
-rw-r--r-- | lib/netdev-linux.c | 131 | ||||
-rw-r--r-- | lib/netdev-provider.h | 82 | ||||
-rw-r--r-- | lib/netdev.c | 227 | ||||
-rw-r--r-- | lib/netdev.h | 7 | ||||
-rw-r--r-- | lib/odp-util.c | 5 | ||||
-rw-r--r-- | lib/ofp-print.c | 15 | ||||
-rw-r--r-- | lib/pcap.c | 2 | ||||
-rw-r--r-- | lib/poll-loop.c | 3 | ||||
-rw-r--r-- | lib/socket-util.c | 37 | ||||
-rw-r--r-- | lib/socket-util.h | 4 | ||||
-rw-r--r-- | lib/stream-tcp.c | 4 | ||||
-rw-r--r-- | lib/svec.c | 16 | ||||
-rw-r--r-- | lib/svec.h | 1 | ||||
-rw-r--r-- | lib/timeval.c | 18 | ||||
-rw-r--r-- | lib/unixctl.c | 2 | ||||
-rw-r--r-- | lib/vconn-ssl.c | 4 | ||||
-rw-r--r-- | lib/vconn-tcp.c | 4 | ||||
-rw-r--r-- | lib/vconn.c | 23 | ||||
-rw-r--r-- | lib/vlog-modules.def | 1 | ||||
-rw-r--r-- | lib/vlog-unixctl.man | 4 | ||||
-rw-r--r-- | lib/vlog.man | 4 |
36 files changed, 634 insertions, 136 deletions
diff --git a/lib/backtrace.c b/lib/backtrace.c index 0999a081e..2f4780932 100644 --- a/lib/backtrace.c +++ b/lib/backtrace.c @@ -42,7 +42,7 @@ get_max_stack(void) for (line_number = 1; fgets(line, sizeof line, f); line_number++) { if (strstr(line, "[stack]")) { uintptr_t end; - if (sscanf(line, "%*"SCNxPTR"-%"SCNxPTR, &end) != 1) { + if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) { VLOG_WARN("%s:%d: parse error", file_name, line_number); continue; } @@ -73,6 +73,10 @@ stack_low(void) uintptr_t low; asm("movl %%esp,%0" : "=g" (low)); return low; +#elif __x86_64__ + uintptr_t low; + asm("movq %%rsp,%0" : "=g" (low)); + return low; #else /* This causes a warning in GCC that cannot be disabled, so use it only on * non-x86. */ diff --git a/lib/classifier.h b/lib/classifier.h index 8b095e911..194b04e6b 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -25,6 +25,20 @@ * fields after F tend to be wildcarded as well. If this assumption is * violated, then the classifier will still classify flows correctly, but its * performance will suffer. + * + * The classifier uses a collection of CLS_N_FIELDS hash tables for wildcarded + * flows. Each of these tables contains the flows that wildcard a given field + * and do not wildcard any of the fields that precede F in the ordering. The + * key for each hash table is the value of the fields preceding F that are not + * wildcarded. All the flows that fall within a table and have the same key + * are kept as a linked list ordered from highest to lowest priority. + * + * The classifier also maintains a separate hash table of exact-match flows. + * + * To search the classifier we first search the table of exact-match flows, + * since exact-match flows always have highest priority. If there is a match, + * we're done. Otherwise, we search each of the CLS_N_FIELDS hash tables in + * turn, looking for the highest-priority match, and return it (if any). */ #include "flow.h" diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 8216d1870..2bf329f45 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -419,7 +419,7 @@ dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp) return 0; } else { VLOG_WARN_RL(&error_rl, "%s: discarding message truncated " - "from %zu bytes to %d", + "from %"PRIu32" bytes to %d", dpif_name(dpif_), msg->length, retval); error = ERANGE; } diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 8bd9648de..816d4025f 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -373,9 +373,13 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags, if (!internal) { error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev); } else { - char *tapname = xasprintf("tap:%s", devname); - error = netdev_open(tapname, NETDEV_ETH_TYPE_ANY, &netdev); - free(tapname); + error = netdev_create(devname, "tap", NULL); + if (!error) { + error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev); + if (error) { + netdev_destroy(devname); + } + } } if (error) { return error; @@ -468,6 +472,7 @@ static int do_del_port(struct dp_netdev *dp, uint16_t port_no) { struct dp_netdev_port *port; + char *name; int error; error = get_port_by_number(dp, port_no, &port); @@ -480,7 +485,12 @@ do_del_port(struct dp_netdev *dp, uint16_t port_no) dp->n_ports--; dp->serial++; + name = xstrdup(netdev_get_name(port->netdev)); netdev_close(port->netdev); + if (port->internal) { + netdev_destroy(name); + } + free(name); free(port); return 0; @@ -665,7 +675,7 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key) } static void -answer_flow_query(const struct dp_netdev_flow *flow, +answer_flow_query(struct dp_netdev_flow *flow, uint32_t query_flags, struct odp_flow *odp_flow) { if (flow) { @@ -683,6 +693,11 @@ answer_flow_query(const struct dp_netdev_flow *flow, n * sizeof *odp_flow->actions); odp_flow->n_actions = flow->n_actions; } + + if (query_flags & ODPFF_ZERO_TCP_FLAGS) { + flow->tcp_ctl = 0; + } + } else { odp_flow->stats.error = ENOENT; } @@ -696,7 +711,8 @@ dpif_netdev_flow_get(const struct dpif *dpif, struct odp_flow flows[], int n) for (i = 0; i < n; i++) { struct odp_flow *odp_flow = &flows[i]; - answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key), odp_flow); + answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key), + odp_flow->flags, odp_flow); } return 0; } @@ -852,7 +868,7 @@ dpif_netdev_flow_del(struct dpif *dpif, struct odp_flow *odp_flow) flow = dp_netdev_lookup_flow(dp, &odp_flow->key); if (flow) { - answer_flow_query(flow, odp_flow); + answer_flow_query(flow, 0, odp_flow); dp_netdev_free_flow(dp, flow); return 0; } else { @@ -872,7 +888,7 @@ dpif_netdev_flow_list(const struct dpif *dpif, struct odp_flow flows[], int n) if (i >= n) { break; } - answer_flow_query(flow, &flows[i++]); + answer_flow_query(flow, 0, &flows[i++]); } return hmap_count(&dp->flow_table); } diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index bd159b2a9..020e017cd 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -42,7 +42,7 @@ static inline void dpif_assert_class(const struct dpif *dpif, } /* Datapath interface class structure, to be defined by each implementation of - * a datapath interface + * a datapath interface. * * These functions return 0 if successful or a positive errno value on failure, * except where otherwise noted. @@ -52,7 +52,7 @@ static inline void dpif_assert_class(const struct dpif *dpif, * EWOULDBLOCK or EINPROGRESS. We may relax this requirement in the future if * and when we encounter performance problems. */ struct dpif_class { - /* Prefix for names of dpifs in this class, e.g. "udatapath:". + /* Prefix for names of dpifs in this class, e.g. "netdev:". * * One dpif class may have the empty string "" as its prefix, in which case * that dpif class is associated with dpif names that don't match any other diff --git a/lib/dpif.c b/lib/dpif.c index 649c2464c..793eaa118 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -169,13 +169,35 @@ dpif_open(const char *name, struct dpif **dpifp) /* Tries to create and open a new datapath with the given 'name'. Will fail if * a datapath named 'name' already exists. Returns 0 if successful, otherwise * a positive errno value. On success stores a pointer to the datapath in - * '*dpifp', otherwise a null pointer.*/ + * '*dpifp', otherwise a null pointer. */ int dpif_create(const char *name, struct dpif **dpifp) { return do_open(name, true, dpifp); } +/* Tries to open a datapath with the given 'name', creating it if it does not + * exist. Returns 0 if successful, otherwise a positive errno value. On + * success stores a pointer to the datapath in '*dpifp', otherwise a null + * pointer. */ +int +dpif_create_and_open(const char *name, struct dpif **dpifp) +{ + int error; + + error = dpif_create(name, dpifp); + if (error == EEXIST || error == EBUSY) { + error = dpif_open(name, dpifp); + if (error) { + VLOG_WARN("datapath %s already exists but cannot be opened: %s", + name, strerror(error)); + } + } else if (error) { + VLOG_WARN("failed to create datapath %s: %s", name, strerror(error)); + } + return error; +} + /* Closes and frees the connection to 'dpif'. Does not destroy the datapath * itself; call dpif_delete() first, instead, if that is desirable. */ void diff --git a/lib/dpif.h b/lib/dpif.h index 216c09969..1d109c2d2 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -37,6 +37,7 @@ int dp_enumerate(struct svec *); int dpif_open(const char *name, struct dpif **); int dpif_create(const char *name, struct dpif **); +int dpif_create_and_open(const char *name, struct dpif **); void dpif_close(struct dpif *); const char *dpif_name(const struct dpif *); diff --git a/lib/fault.c b/lib/fault.c index 3882eff7c..14e229ed6 100644 --- a/lib/fault.c +++ b/lib/fault.c @@ -54,7 +54,7 @@ log_backtrace(void) if (!dladdr(frame[1], &addrinfo) || !addrinfo.dli_sname) { fprintf(stderr, " 0x%08"PRIxPTR"\n", (uintptr_t) frame[1]); } else { - fprintf(stderr, " 0x%08"PRIxPTR" (%s+0x%x)\n", + fprintf(stderr, " 0x%08"PRIxPTR" (%s+0x%tx)\n", (uintptr_t) frame[1], addrinfo.dli_sname, (char *) frame[1] - (char *) addrinfo.dli_saddr); } diff --git a/lib/flow.c b/lib/flow.c index c1f6240f0..7d4a1bd4d 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -317,7 +317,7 @@ flow_to_string(const flow_t *flow) void flow_format(struct ds *ds, const flow_t *flow) { - ds_put_format(ds, "port%04x:vlan%d mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" " + ds_put_format(ds, "in_port%04x:vlan%d mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" " "type%04x proto%"PRId8" ip"IP_FMT"->"IP_FMT" port%d->%d", flow->in_port, ntohs(flow->dl_vlan), ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst), diff --git a/lib/leak-checker.c b/lib/leak-checker.c index c2c4348f5..8d256bc8c 100644 --- a/lib/leak-checker.c +++ b/lib/leak-checker.c @@ -141,7 +141,7 @@ log_callers(const char *format, ...) putc(':', file); backtrace_capture(&backtrace); for (i = 0; i < backtrace.n_frames; i++) { - fprintf(file, " 0x%x", backtrace.frames[i]); + fprintf(file, " 0x%"PRIxPTR, backtrace.frames[i]); } putc('\n', file); } diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 99d5ee4c0..78346acbb 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -57,6 +57,8 @@ struct lswitch { uint32_t capabilities; time_t last_features_request; struct mac_learning *ml; /* NULL to act as hub instead of switch. */ + bool exact_flows; /* Use exact-match flows? */ + bool action_normal; /* Use OFPP_NORMAL? */ /* Number of outgoing queued packets on the rconn. */ struct rconn_packet_counter *queued; @@ -105,7 +107,8 @@ static packet_handler_func process_stats_reply; * * 'rconn' is used to send out an OpenFlow features request. */ struct lswitch * -lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle) +lswitch_create(struct rconn *rconn, bool learn_macs, + bool exact_flows, int max_idle, bool action_normal) { struct lswitch *sw; size_t i; @@ -115,6 +118,8 @@ lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle) sw->datapath_id = 0; sw->last_features_request = time_now() - 1; sw->ml = learn_macs ? mac_learning_create() : NULL; + sw->action_normal = action_normal; + sw->exact_flows = exact_flows; sw->queued = rconn_packet_counter_create(); sw->next_query = LLONG_MIN; sw->last_query = LLONG_MIN; @@ -430,10 +435,34 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_) /* Don't send out packets on their input ports. */ goto drop_it; } else if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) { + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + uint32_t wildcards; + + /* Check if we need to wildcard the flows. */ + if (!sw->exact_flows) { + /* We can not wildcard all fields. + * We need in_port to detect moves. + * We need both SA and DA to do learning. */ + wildcards = (OFPFW_DL_TYPE | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK + | OFPFW_NW_PROTO | OFPFW_TP_SRC | OFPFW_TP_DST); + } else { + /* Exact match */ + wildcards = 0; + } + + /* Check if we need to use "NORMAL" action. */ + if (sw->action_normal && out_port != OFPP_FLOOD) { + out_port = OFPP_NORMAL; + } + /* The output port is known, or we always flood everything, so add a * new flow. */ - queue_tx(sw, rconn, make_add_simple_flow(&flow, ntohl(opi->buffer_id), - out_port, sw->max_idle)); + buffer = make_add_simple_flow(&flow, ntohl(opi->buffer_id), + out_port, sw->max_idle); + ofm = buffer->data; + ofm->match.wildcards = htonl(wildcards); + queue_tx(sw, rconn, buffer); /* If the switch didn't buffer the packet, we need to send a copy. */ if (ntohl(opi->buffer_id) == UINT32_MAX) { @@ -441,9 +470,15 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_) make_unbuffered_packet_out(&pkt, in_port, out_port)); } } else { + struct ofpbuf *b; + + /* Check if we need to use "NORMAL" action. */ + if (sw->action_normal && out_port != OFPP_FLOOD) { + out_port = OFPP_NORMAL; + } + /* We don't know that MAC, or we don't set up flows. Send along the * packet without setting up a flow. */ - struct ofpbuf *b; if (ntohl(opi->buffer_id) == UINT32_MAX) { b = make_unbuffered_packet_out(&pkt, in_port, out_port); } else { diff --git a/lib/learning-switch.h b/lib/learning-switch.h index 8837d6470..2de862e6d 100644 --- a/lib/learning-switch.h +++ b/lib/learning-switch.h @@ -22,7 +22,9 @@ struct ofpbuf; struct rconn; -struct lswitch *lswitch_create(struct rconn *, bool learn_macs, int max_idle); +struct lswitch *lswitch_create(struct rconn *, bool learn_macs, + bool exact_flows, int max_idle, + bool action_normal); void lswitch_run(struct lswitch *, struct rconn *); void lswitch_wait(struct lswitch *); void lswitch_destroy(struct lswitch *); diff --git a/lib/lockfile.c b/lib/lockfile.c index e5a041eed..9bb7c6b18 100644 --- a/lib/lockfile.c +++ b/lib/lockfile.c @@ -61,8 +61,8 @@ lockfile_name(const char *file_name) { const char *slash = strrchr(file_name, '/'); return (slash - ? xasprintf("%.*s/.%s.~lock~", slash - file_name, file_name, - slash + 1) + ? xasprintf("%.*s/.%s.~lock~", + (int) (slash - file_name), file_name, slash + 1) : xasprintf(".%s.~lock~", file_name)); } diff --git a/lib/mac-learning.c b/lib/mac-learning.c index c9b7d3e73..3f1db1461 100644 --- a/lib/mac-learning.c +++ b/lib/mac-learning.c @@ -21,6 +21,7 @@ #include <inttypes.h> #include <stdlib.h> +#include "bitmap.h" #include "coverage.h" #include "hash.h" #include "list.h" @@ -129,6 +130,7 @@ mac_learning_create(void) list_push_front(&ml->free, &s->lru_node); } ml->secret = random_uint32(); + ml->non_learning_vlans = NULL; return ml; } @@ -136,9 +138,36 @@ mac_learning_create(void) void mac_learning_destroy(struct mac_learning *ml) { + if (ml) { + bitmap_free(ml->non_learning_vlans); + } free(ml); } +/* Provides a bitmap of VLANs which have learning disabled. It takes + * ownership of the bitmap. Returns true if the set has changed from + * the previous value. */ +bool +mac_learning_set_disabled_vlans(struct mac_learning *ml, unsigned long *bitmap) +{ + bool ret = (bitmap == NULL + ? ml->non_learning_vlans != NULL + : (ml->non_learning_vlans == NULL + || !bitmap_equal(bitmap, ml->non_learning_vlans, 4096))); + + bitmap_free(ml->non_learning_vlans); + ml->non_learning_vlans = bitmap; + + return ret; +} + +static bool +is_learning_vlan(const struct mac_learning *ml, uint16_t vlan) +{ + return !(ml->non_learning_vlans + && bitmap_is_set(ml->non_learning_vlans, vlan)); +} + /* Attempts to make 'ml' learn from the fact that a frame from 'src_mac' was * just observed arriving from 'src_port' on the given 'vlan'. * @@ -156,6 +185,10 @@ mac_learning_learn(struct mac_learning *ml, struct mac_entry *e; struct list *bucket; + if (!is_learning_vlan(ml, vlan)) { + return 0; + } + if (eth_addr_is_multicast(src_mac)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 30); VLOG_DBG_RL(&rl, "multicast packet source "ETH_ADDR_FMT, @@ -216,7 +249,7 @@ mac_learning_lookup_tag(const struct mac_learning *ml, const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan, tag_type *tag) { - if (eth_addr_is_multicast(dst)) { + if (eth_addr_is_multicast(dst) || !is_learning_vlan(ml, vlan)) { return -1; } else { struct mac_entry *e = search_bucket(mac_table_bucket(ml, dst, vlan), diff --git a/lib/mac-learning.h b/lib/mac-learning.h index e2ee74ba4..ed843cd45 100644 --- a/lib/mac-learning.h +++ b/lib/mac-learning.h @@ -52,10 +52,13 @@ struct mac_learning { struct list table[MAC_HASH_SIZE]; /* Hash table. */ struct mac_entry entries[MAC_MAX]; /* All entries. */ uint32_t secret; /* Secret for */ + unsigned long *non_learning_vlans; /* Bitmap of learning disabled VLANs. */ }; struct mac_learning *mac_learning_create(void); void mac_learning_destroy(struct mac_learning *); +bool mac_learning_set_disabled_vlans(struct mac_learning *, + unsigned long *bitmap); tag_type mac_learning_learn(struct mac_learning *, const uint8_t src[ETH_ADDR_LEN], uint16_t vlan, uint16_t src_port); diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index c33405fd3..47d89efa1 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -67,6 +67,14 @@ #define ADVERTISED_Asym_Pause (1 << 14) #endif +/* Provider-specific netdev object. Netdev objects are devices that are + * created by the netdev library through a netdev_create() call. */ +struct netdev_obj_linux { + struct netdev_obj netdev_obj; + + int tap_fd; /* File descriptor for TAP device. */ +}; + struct netdev_linux { struct netdev netdev; @@ -142,6 +150,13 @@ static int set_etheraddr(const char *netdev_name, int hwaddr_family, static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats); static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats); +static struct netdev_obj_linux * +netdev_obj_linux_cast(const struct netdev_obj *netdev_obj) +{ + netdev_obj_assert_class(netdev_obj, &netdev_linux_class); + return CONTAINER_OF(netdev_obj, struct netdev_obj_linux, netdev_obj); +} + static struct netdev_linux * netdev_linux_cast(const struct netdev *netdev) { @@ -194,9 +209,77 @@ netdev_linux_cache_cb(const struct rtnetlink_change *change, } } +/* Creates the netdev object of 'type' with 'name'. */ +static int +netdev_linux_create(const char *name, const char *type, + const struct shash *args, bool created) +{ + struct netdev_obj_linux *netdev_obj; + static const char tap_dev[] = "/dev/net/tun"; + struct ifreq ifr; + int error; + + if (!shash_is_empty(args)) { + VLOG_WARN("arguments for %s devices should be empty", type); + } + + /* Create the name binding in the netdev library for this object. */ + netdev_obj = xcalloc(1, sizeof *netdev_obj); + netdev_obj_init(&netdev_obj->netdev_obj, name, &netdev_linux_class, + created); + netdev_obj->tap_fd = -1; + + if (strcmp(type, "tap")) { + return 0; + } + + /* Open tap device. */ + netdev_obj->tap_fd = open(tap_dev, O_RDWR); + if (netdev_obj->tap_fd < 0) { + error = errno; + VLOG_WARN("opening \"%s\" failed: %s", tap_dev, strerror(error)); + goto error; + } + + /* Create tap device. */ + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + if (ioctl(netdev_obj->tap_fd, TUNSETIFF, &ifr) == -1) { + VLOG_WARN("%s: creating tap device failed: %s", name, + strerror(errno)); + error = errno; + goto error; + } + + /* Make non-blocking. */ + error = set_nonblocking(netdev_obj->tap_fd); + if (error) { + goto error; + } + + return 0; + +error: + netdev_destroy(name); + return error; +} + +/* Destroys the netdev object 'netdev_obj_'. */ +static void +netdev_linux_destroy(struct netdev_obj *netdev_obj_) +{ + struct netdev_obj_linux *netdev_obj = netdev_obj_linux_cast(netdev_obj_); + + if (netdev_obj->tap_fd >= 0) { + close(netdev_obj->tap_fd); + } + free(netdev_obj); + + return; +} + static int -netdev_linux_open(const char *name, char *suffix, int ethertype, - struct netdev **netdevp) +netdev_linux_open(const char *name, int ethertype, struct netdev **netdevp) { struct netdev_linux *netdev; enum netdev_flags flags; @@ -204,10 +287,10 @@ netdev_linux_open(const char *name, char *suffix, int ethertype, /* Allocate network device. */ netdev = xzalloc(sizeof *netdev); - netdev_init(&netdev->netdev, suffix, &netdev_linux_class); + netdev_init(&netdev->netdev, name, &netdev_linux_class); netdev->netdev_fd = -1; netdev->tap_fd = -1; - netdev->cache = shash_find_data(&cache_map, suffix); + netdev->cache = shash_find_data(&cache_map, name); if (!netdev->cache) { if (shash_is_empty(&cache_map)) { int error = rtnetlink_notifier_register( @@ -218,14 +301,14 @@ netdev_linux_open(const char *name, char *suffix, int ethertype, } } netdev->cache = xmalloc(sizeof *netdev->cache); - netdev->cache->shash_node = shash_add(&cache_map, suffix, + netdev->cache->shash_node = shash_add(&cache_map, name, netdev->cache); netdev->cache->valid = 0; netdev->cache->ref_cnt = 0; } netdev->cache->ref_cnt++; - if (!strncmp(name, "tap:", 4)) { + if (!strcmp(netdev_get_type(&netdev->netdev), "tap")) { static const char tap_dev[] = "/dev/net/tun"; struct ifreq ifr; @@ -239,9 +322,9 @@ netdev_linux_open(const char *name, char *suffix, int ethertype, /* Create tap device. */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strncpy(ifr.ifr_name, suffix, sizeof ifr.ifr_name); + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if (ioctl(netdev->tap_fd, TUNSETIFF, &ifr) == -1) { - VLOG_WARN("%s: creating tap device failed: %s", suffix, + VLOG_WARN("%s: creating tap device failed: %s", name, strerror(errno)); error = errno; goto error; @@ -296,7 +379,7 @@ netdev_linux_open(const char *name, char *suffix, int ethertype, if (bind(netdev->netdev_fd, (struct sockaddr *) &sll, sizeof sll) < 0) { error = errno; - VLOG_ERR("bind to %s failed: %s", suffix, strerror(error)); + VLOG_ERR("bind to %s failed: %s", name, strerror(error)); goto error; } @@ -548,6 +631,17 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup) return 0; } +/* Returns the ifindex of 'netdev', if successful, as a positive number. + * On failure, returns a negative errno value. */ +static int +netdev_linux_get_ifindex(const struct netdev *netdev) +{ + int ifindex, error; + + error = get_ifindex(netdev, &ifindex); + return error ? -error : ifindex; +} + static int netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier) { @@ -720,8 +814,7 @@ netdev_linux_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) /* Stores the features supported by 'netdev' into each of '*current', * '*advertised', '*supported', and '*peer' that are non-null. Each value is a * bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if - * successful, otherwise a positive errno value. On failure, all of the - * passed-in values are set to 0. */ + * successful, otherwise a positive errno value. */ static int netdev_linux_get_features(struct netdev *netdev, uint32_t *current, uint32_t *advertised, @@ -1367,13 +1460,16 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) } const struct netdev_class netdev_linux_class = { - "", /* prefix */ - "linux", /* name */ + "system", /* type */ netdev_linux_init, netdev_linux_run, netdev_linux_wait, + netdev_linux_create, + netdev_linux_destroy, + NULL, /* reconfigure */ + netdev_linux_open, netdev_linux_close, @@ -1389,6 +1485,7 @@ const struct netdev_class netdev_linux_class = { netdev_linux_set_etheraddr, netdev_linux_get_etheraddr, netdev_linux_get_mtu, + netdev_linux_get_ifindex, netdev_linux_get_carrier, netdev_linux_get_stats, @@ -1411,13 +1508,16 @@ const struct netdev_class netdev_linux_class = { }; const struct netdev_class netdev_tap_class = { - "tap", /* prefix */ - "tap", /* name */ + "tap", /* type */ netdev_linux_init, NULL, /* run */ NULL, /* wait */ + netdev_linux_create, + netdev_linux_destroy, + NULL, /* reconfigure */ + netdev_linux_open, netdev_linux_close, @@ -1433,6 +1533,7 @@ const struct netdev_class netdev_tap_class = { netdev_linux_set_etheraddr, netdev_linux_get_etheraddr, netdev_linux_get_mtu, + netdev_linux_get_ifindex, netdev_linux_get_carrier, netdev_linux_get_stats, diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 3bc7fd444..64d227e8d 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -22,6 +22,26 @@ #include <assert.h> #include "netdev.h" #include "list.h" +#include "shash.h" + +/* A network device object that was created through the netdev_create() + * call. + * + * This structure should be treated as opaque by network device + * implementations. */ +struct netdev_obj { + const struct netdev_class *class; + int ref_cnt; + bool created; /* Was netdev_create() called? */ +}; + +void netdev_obj_init(struct netdev_obj *, const char *name, + const struct netdev_class *, bool created); +static inline void netdev_obj_assert_class(const struct netdev_obj *netdev_obj, + const struct netdev_class *class) +{ + assert(netdev_obj->class == class); +} /* A network device (e.g. an Ethernet device). * @@ -30,6 +50,7 @@ struct netdev { const struct netdev_class *class; char *name; /* e.g. "eth0" */ + enum netdev_flags save_flags; /* Initial device flags. */ enum netdev_flags changed_flags; /* Flags that we changed. */ struct list node; /* Element in global list. */ @@ -42,6 +63,7 @@ static inline void netdev_assert_class(const struct netdev *netdev, { assert(netdev->class == class); } +const char *netdev_get_type(const struct netdev *netdev); /* A network device notifier. * @@ -62,15 +84,13 @@ void netdev_notifier_init(struct netdev_notifier *, struct netdev *, * These functions return 0 if successful or a positive errno value on failure, * except where otherwise noted. */ struct netdev_class { - /* Prefix for names of netdevs in this class, e.g. "ndunix:". + /* Type of netdevs in this class, e.g. "system", "tap", "gre", etc. * - * One netdev class may have the empty string "" as its prefix, in which - * case that netdev class is associated with netdev names that do not - * contain a colon. */ - const char *prefix; - - /* Class name, for use in error messages. */ - const char *name; + * One of the providers should supply a "system" type, since this is + * the type assumed when a device name was not bound through the + * netdev_create() call. The "system" type corresponds to an + * existing network device on the system. */ + const char *type; /* Called only once, at program startup. Returning an error from this * function will prevent any network device in this class from being @@ -88,19 +108,45 @@ struct netdev_class { * to be called. May be null if nothing is needed here. */ void (*wait)(void); + /* Attempts to create a network device object of 'type' with 'name'. + * 'type' corresponds to the 'type' field used in the netdev_class + * structure. + * + * The 'created' flag indicates that the user called netdev_create() + * and thus will eventually call netdev_destroy(). If the flag is + * false, then the object was dynamically created based on a call to + * netdev_open() without first calling netdev_create() and will be + * automatically destroyed when no more netdevs have 'name' open. A + * provider implementation should pass this flag to netdev_obj_init(). */ + int (*create)(const char *name, const char *type, + const struct shash *args, bool created); + + /* Destroys 'netdev_obj'. + * + * Netdev objects maintain a reference count that is incremented on + * netdev_open() and decremented on netdev_close(). If 'netdev_obj' + * has a non-zero reference count, then this function will not be + * called. */ + void (*destroy)(struct netdev_obj *netdev_obj); + + /* Reconfigures the device object 'netdev_obj' with 'args'. + * + * If this netdev class does not support reconfiguring a netdev + * object, this may be a null pointer. + */ + int (*reconfigure)(struct netdev_obj *netdev_obj, + const struct shash *args); + /* Attempts to open a network device. On success, sets '*netdevp' to the - * new network device. 'name' is the full network device name provided by + * new network device. 'name' is the network device name provided by * the user. This name is useful for error messages but must not be * modified. * - * 'suffix' is a copy of 'name' following the netdev's 'prefix'. - * * 'ethertype' may be a 16-bit Ethernet protocol value in host byte order * to capture frames of that type received on the device. It may also be * one of the 'enum netdev_pseudo_ethertype' values to receive frames in * one of those categories. */ - int (*open)(const char *name, char *suffix, int ethertype, - struct netdev **netdevp); + int (*open)(const char *name, int ethertype, struct netdev **netdevp); /* Closes 'netdev'. */ void (*close)(struct netdev *netdev); @@ -164,6 +210,16 @@ struct netdev_class { * bytes for Ethernet devices.*/ int (*get_mtu)(const struct netdev *, int *mtup); + /* Returns the ifindex of 'netdev', if successful, as a positive number. + * On failure, returns a negative errno value. + * + * The desired semantics of the ifindex value are a combination of those + * specified by POSIX for if_nametoindex() and by SNMP for ifIndex. An + * ifindex value should be unique within a host and remain stable at least + * until reboot. SNMP says an ifindex "ranges between 1 and the value of + * ifNumber" but many systems do not follow this rule anyhow. */ + int (*get_ifindex)(const struct netdev *); + /* Sets 'carrier' to true if carrier is active (link light is on) on * 'netdev'. */ int (*get_carrier)(const struct netdev *netdev, bool *carrier); diff --git a/lib/netdev.c b/lib/netdev.c index 481671f79..fb0f98e6e 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -45,6 +45,9 @@ static const struct netdev_class *netdev_classes[] = { }; static int n_netdev_classes = ARRAY_SIZE(netdev_classes); +/* All created network devices. */ +static struct shash netdev_obj_shash = SHASH_INITIALIZER(&netdev_obj_shash); + /* All open network devices. */ static struct list netdev_list = LIST_INITIALIZER(&netdev_list); @@ -59,7 +62,8 @@ static int restore_flags(struct netdev *netdev); * otherwise a positive errno value. * * Calling this function is optional. If not called explicitly, it will - * automatically be called upon the first attempt to open a network device. */ + * automatically be called upon the first attempt to open or create a + * network device. */ int netdev_initialize(void) { @@ -78,7 +82,7 @@ netdev_initialize(void) netdev_classes[j++] = class; } else { VLOG_ERR("failed to initialize %s network device " - "class: %s", class->name, strerror(retval)); + "class: %s", class->type, strerror(retval)); if (!status) { status = retval; } @@ -124,6 +128,92 @@ netdev_wait(void) } } +/* Attempts to create a network device object of 'type' with 'name'. 'type' + * corresponds to the 'type' field used in the netdev_class * structure. + * Arguments for creation are provided in 'args', which may be empty or NULL + * if none are needed. */ +int +netdev_create(const char *name, const char *type, const struct shash *args) +{ + struct shash empty_args = SHASH_INITIALIZER(&empty_args); + int i; + + netdev_initialize(); + + if (!args) { + args = &empty_args; + } + + if (shash_find(&netdev_obj_shash, name)) { + VLOG_WARN("attempted to create a netdev object with bound name: %s", + name); + return EEXIST; + } + + for (i = 0; i < n_netdev_classes; i++) { + const struct netdev_class *class = netdev_classes[i]; + if (!strcmp(type, class->type)) { + return class->create(name, type, args, true); + } + } + + VLOG_WARN("could not create netdev object of unknown type: %s", type); + + return EINVAL; +} + +/* Destroys netdev object 'name'. Netdev objects maintain a reference count + * which is incremented on netdev_open() and decremented on netdev_close(). + * If 'name' has a non-zero reference count, it will not destroy the object + * and return EBUSY. */ +int +netdev_destroy(const char *name) +{ + struct shash_node *node; + struct netdev_obj *netdev_obj; + + node = shash_find(&netdev_obj_shash, name); + if (!node) { + return ENODEV; + } + + netdev_obj = node->data; + if (netdev_obj->ref_cnt != 0) { + VLOG_WARN("attempt to destroy open netdev object (%d): %s", + netdev_obj->ref_cnt, name); + return EBUSY; + } + + shash_delete(&netdev_obj_shash, node); + netdev_obj->class->destroy(netdev_obj); + + return 0; +} + +/* Reconfigures the device object 'name' with 'args'. 'args' may be empty + * or NULL if none are needed. */ +int +netdev_reconfigure(const char *name, const struct shash *args) +{ + struct shash empty_args = SHASH_INITIALIZER(&empty_args); + struct netdev_obj *netdev_obj; + + if (!args) { + args = &empty_args; + } + + netdev_obj = shash_find_data(&netdev_obj_shash, name); + if (!netdev_obj) { + return ENODEV; + } + + if (netdev_obj->class->reconfigure) { + return netdev_obj->class->reconfigure(netdev_obj, args); + } + + return 0; +} + /* Opens the network device named 'name' (e.g. "eth0") and returns zero if * successful, otherwise a positive errno value. On success, sets '*netdevp' * to the new network device, otherwise to null. @@ -133,37 +223,43 @@ netdev_wait(void) * the 'enum netdev_pseudo_ethertype' values to receive frames in one of those * categories. */ int -netdev_open(const char *name_, int ethertype, struct netdev **netdevp) +netdev_open(const char *name, int ethertype, struct netdev **netdevp) { - char *name = xstrdup(name_); - char *prefix, *suffix, *colon; + struct netdev_obj *netdev_obj; struct netdev *netdev = NULL; int error; int i; netdev_initialize(); - colon = strchr(name, ':'); - if (colon) { - *colon = '\0'; - prefix = name; - suffix = colon + 1; + + netdev_obj = shash_find_data(&netdev_obj_shash, name); + if (netdev_obj) { + error = netdev_obj->class->open(name, ethertype, &netdev); } else { - prefix = ""; - suffix = name; - } + /* Default to "system". */ + error = EAFNOSUPPORT; + for (i = 0; i < n_netdev_classes; i++) { + const struct netdev_class *class = netdev_classes[i]; + if (!strcmp(class->type, "system")) { + struct shash empty_args = SHASH_INITIALIZER(&empty_args); - 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); - goto exit; + /* Dynamically create the netdev object, but indicate + * that it should be destroyed when the the last user + * closes its handle. */ + error = class->create(name, "system", &empty_args, false); + if (!error) { + error = class->open(name, ethertype, &netdev); + netdev_obj = shash_find_data(&netdev_obj_shash, name); + } + break; + } } } - error = EAFNOSUPPORT; + if (!error) { + netdev_obj->ref_cnt++; + } -exit: *netdevp = error ? NULL : netdev; - free(name); return error; } @@ -172,9 +268,24 @@ void netdev_close(struct netdev *netdev) { if (netdev) { - char *name; + struct netdev_obj *netdev_obj; + char *name = netdev->name; int error; + netdev_obj = shash_find_data(&netdev_obj_shash, name); + assert(netdev_obj); + if (netdev_obj->ref_cnt > 0) { + netdev_obj->ref_cnt--; + } else { + VLOG_WARN("netdev %s closed too many times", name); + } + + /* If the reference count for the netdev object is zero, and it + * was dynamically created by netdev_open(), destroy it. */ + if (!netdev_obj->ref_cnt && !netdev_obj->created) { + netdev_destroy(name); + } + /* Restore flags that we changed, if any. */ fatal_signal_block(); error = restore_flags(netdev); @@ -182,11 +293,10 @@ netdev_close(struct netdev *netdev) fatal_signal_unblock(); if (error) { VLOG_WARN("failed to restore network device flags on %s: %s", - netdev->name, strerror(error)); + name, strerror(error)); } /* Free. */ - name = netdev->name; netdev->class->close(netdev); free(name); } @@ -231,7 +341,7 @@ netdev_enumerate(struct svec *svec) int retval = class->enumerate(svec); if (retval) { VLOG_WARN("failed to enumerate %s network devices: %s", - class->name, strerror(retval)); + class->type, strerror(retval)); if (!error) { error = retval; } @@ -366,6 +476,21 @@ netdev_get_mtu(const struct netdev *netdev, int *mtup) return error; } +/* Returns the ifindex of 'netdev', if successful, as a positive number. On + * failure, returns a negative errno value. + * + * The desired semantics of the ifindex value are a combination of those + * specified by POSIX for if_nametoindex() and by SNMP for ifIndex. An ifindex + * value should be unique within a host and remain stable at least until + * reboot. SNMP says an ifindex "ranges between 1 and the value of ifNumber" + * but many systems do not follow this rule anyhow. + */ +int +netdev_get_ifindex(const struct netdev *netdev) +{ + return netdev->class->get_ifindex(netdev); +} + /* Stores the features supported by 'netdev' into each of '*current', * '*advertised', '*supported', and '*peer' that are non-null. Each value is a * bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if @@ -377,11 +502,27 @@ netdev_get_features(struct netdev *netdev, uint32_t *supported, uint32_t *peer) { uint32_t dummy[4]; - return netdev->class->get_features(netdev, - current ? current : &dummy[0], - advertised ? advertised : &dummy[1], - supported ? supported : &dummy[2], - peer ? peer : &dummy[3]); + int error; + + if (!current) { + current = &dummy[0]; + } + if (!advertised) { + advertised = &dummy[1]; + } + if (!supported) { + supported = &dummy[2]; + } + if (!peer) { + peer = &dummy[3]; + } + + error = netdev->class->get_features(netdev, current, advertised, supported, + peer); + if (error) { + *current = *advertised = *supported = *peer = 0; + } + return error; } /* Set the features advertised by 'netdev' to 'advertise'. Returns 0 if @@ -677,6 +818,24 @@ exit: return netdev; } +/* Initializes 'netdev_obj' as a netdev object named 'name' of the + * specified 'class'. + * + * This function adds 'netdev_obj' to a netdev-owned shash, so it is + * very important that 'netdev_obj' only be freed after calling + * netdev_destroy(). */ +void +netdev_obj_init(struct netdev_obj *netdev_obj, const char *name, + const struct netdev_class *class, bool created) +{ + assert(!shash_find(&netdev_obj_shash, name)); + + netdev_obj->class = class; + netdev_obj->ref_cnt = 0; + netdev_obj->created = created; + shash_add(&netdev_obj_shash, name, netdev_obj); +} + /* Initializes 'netdev' as a netdev named 'name' of the specified 'class'. * * This function adds 'netdev' to a netdev-owned linked list, so it is very @@ -692,6 +851,14 @@ netdev_init(struct netdev *netdev, const char *name, list_push_back(&netdev_list, &netdev->node); } +/* Returns the class type of 'netdev'. + * + * The caller must not free the returned value. */ +const char *netdev_get_type(const struct netdev *netdev) +{ + return netdev->class->type; +} + /* Initializes 'notifier' as a netdev notifier for 'netdev', for which * notification will consist of calling 'cb', with auxiliary data 'aux'. */ void diff --git a/lib/netdev.h b/lib/netdev.h index 4a29cf374..b8c7dfb49 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -30,6 +30,7 @@ struct ofpbuf; struct in_addr; struct in6_addr; +struct shash; struct svec; enum netdev_flags { @@ -81,6 +82,11 @@ int netdev_initialize(void); void netdev_run(void); void netdev_wait(void); +int netdev_create(const char *name, const char *type, + const struct shash *args); +int netdev_destroy(const char *name); +int netdev_reconfigure(const char *name, const struct shash *args); + int netdev_open(const char *name, int ethertype, struct netdev **); void netdev_close(struct netdev *); @@ -90,6 +96,7 @@ int netdev_enumerate(struct svec *); const char *netdev_get_name(const struct netdev *); int netdev_get_mtu(const struct netdev *, int *mtup); +int netdev_get_ifindex(const struct netdev *); int netdev_recv(struct netdev *, struct ofpbuf *); void netdev_recv_wait(struct netdev *); diff --git a/lib/odp-util.c b/lib/odp-util.c index 21bc9a516..a80016209 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -111,8 +111,9 @@ format_odp_actions(struct ds *ds, const union odp_action *actions, void format_odp_flow_stats(struct ds *ds, const struct odp_flow_stats *s) { - ds_put_format(ds, "packets:%"PRIu64", bytes:%"PRIu64", used:", - s->n_packets, s->n_bytes); + ds_put_format(ds, "packets:%llu, bytes:%llu, used:", + (unsigned long long int) s->n_packets, + (unsigned long long int) s->n_bytes); if (s->used_sec) { long long int used = s->used_sec * 1000 + s->used_nsec / 1000000; ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 63b59ddb0..9c1afe448 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -797,7 +797,11 @@ static const struct error_type error_types[] = { ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION), ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE), ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT), - ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION), + ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR), + ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE), + ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH), + ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY), + ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE), ERROR_TYPE(OFPET_BAD_ACTION), ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE), @@ -805,9 +809,16 @@ static const struct error_type error_types[] = { ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR), ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE), ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT), + ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT), + ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_TOO_MANY), ERROR_TYPE(OFPET_FLOW_MOD_FAILED), - ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL) + ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL), + ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND), + + ERROR_TYPE(OFPET_PORT_MOD_FAILED), + ERROR_CODE(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT), + ERROR_CODE(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR) }; #define N_ERROR_TYPES ARRAY_SIZE(error_types) diff --git a/lib/pcap.c b/lib/pcap.c index 4330c575d..967bb5c34 100644 --- a/lib/pcap.c +++ b/lib/pcap.c @@ -128,7 +128,7 @@ pcap_read(FILE *file, struct ofpbuf **bufp) ((len & 0x0000ff00) << 8) | ((len & 0x000000ff) << 24)); if (swapped_len > 0xffff) { - VLOG_WARN("bad packet length %"PRIu32" or %"PRIu32" " + VLOG_WARN("bad packet length %zu or %"PRIu32" " "reading pcap file", len, swapped_len); return EPROTO; diff --git a/lib/poll-loop.c b/lib/poll-loop.c index 26a17e83f..32bbc1349 100644 --- a/lib/poll-loop.c +++ b/lib/poll-loop.c @@ -18,6 +18,7 @@ #include "poll-loop.h" #include <assert.h> #include <errno.h> +#include <inttypes.h> #include <poll.h> #include <stdlib.h> #include <string.h> @@ -122,7 +123,7 @@ log_wakeup(const struct backtrace *backtrace, const char *format, ...) ds_put_char(&ds, ':'); for (i = 0; i < backtrace->n_frames; i++) { - ds_put_format(&ds, " 0x%x", backtrace->frames[i]); + ds_put_format(&ds, " 0x%"PRIxPTR, backtrace->frames[i]); } } VLOG_DBG("%s", ds_cstr(&ds)); diff --git a/lib/socket-util.c b/lib/socket-util.c index e400bb543..e6a6c70ef 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -291,10 +291,12 @@ guess_netmask(uint32_t ip) : htonl(0)); /* ??? */ } -/* Opens a non-blocking TCP socket and connects to 'target', which should be a - * string in the format "<host>[:<port>]". <host> is required. If - * 'default_port' is nonzero then <port> is optional and defaults to - * 'default_port'. +/* Opens a non-blocking IPv4 socket of the specified 'style' and connects to + * 'target', which should be a string in the format "<host>[:<port>]". <host> + * is required. If 'default_port' is nonzero then <port> is optional and + * defaults to 'default_port'. + * + * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP). * * On success, returns 0 (indicating connection complete) or EAGAIN (indicating * connection in progress), in which case the new file descriptor is stored @@ -304,8 +306,8 @@ guess_netmask(uint32_t ip) * If 'sinp' is non-null, then on success the target address is stored into * '*sinp'. */ int -tcp_open_active(const char *target_, uint16_t default_port, - struct sockaddr_in *sinp, int *fdp) +inet_open_active(int style, const char *target_, uint16_t default_port, + struct sockaddr_in *sinp, int *fdp) { char *target = xstrdup(target_); char *save_ptr = NULL; @@ -343,7 +345,7 @@ tcp_open_active(const char *target_, uint16_t default_port, } /* Create non-blocking socket. */ - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, style, 0); if (fd < 0) { VLOG_ERR("%s: socket: %s", target_, strerror(errno)); error = errno; @@ -380,18 +382,20 @@ exit: return error; } -/* Opens a non-blocking TCP socket, binds to 'target', and listens for incoming - * connections. 'target' should be a string in the format "[<port>][:<ip>]". - * <port> may be omitted if 'default_port' is nonzero, in which case it - * defaults to 'default_port'. If <ip> is omitted it defaults to the wildcard - * IP address. +/* Opens a non-blocking IPv4 socket of the specified 'style', binds to + * 'target', and listens for incoming connections. 'target' should be a string + * in the format "[<port>][:<ip>]". <port> may be omitted if 'default_port' is + * nonzero, in which case it defaults to 'default_port'. If <ip> is omitted it + * defaults to the wildcard IP address. + * + * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP). * - * The socket will have SO_REUSEADDR turned on. + * For TCP, the socket will have SO_REUSEADDR turned on. * * On success, returns a non-negative file descriptor. On failure, returns a * negative errno value. */ int -tcp_open_passive(const char *target_, uint16_t default_port) +inet_open_passive(int style, const char *target_, uint16_t default_port) { char *target = xstrdup(target_); char *string_ptr = target; @@ -427,7 +431,7 @@ tcp_open_passive(const char *target_, uint16_t default_port) } /* Create non-blocking socket, set SO_REUSEADDR. */ - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, style, 0); if (fd < 0) { error = errno; VLOG_ERR("%s: socket: %s", target_, strerror(error)); @@ -437,7 +441,8 @@ tcp_open_passive(const char *target_, uint16_t default_port) if (error) { goto exit_close; } - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { + if (style == SOCK_STREAM + && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { error = errno; VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", target_, strerror(error)); goto exit_close; diff --git a/lib/socket-util.h b/lib/socket-util.h index febe5e735..4259115d4 100644 --- a/lib/socket-util.h +++ b/lib/socket-util.h @@ -34,9 +34,9 @@ int get_unix_name_len(socklen_t sun_len); uint32_t guess_netmask(uint32_t ip); int get_null_fd(void); -int tcp_open_active(const char *target, uint16_t default_port, +int inet_open_active(int style, const char *target, uint16_t default_port, struct sockaddr_in *sinp, int *fdp); -int tcp_open_passive(const char *target, uint16_t default_port); +int inet_open_passive(int style, const char *target, uint16_t default_port); int read_fully(int fd, void *, size_t, size_t *bytes_read); int write_fully(int fd, const void *, size_t, size_t *bytes_written); diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c index ecd96865f..947be9f19 100644 --- a/lib/stream-tcp.c +++ b/lib/stream-tcp.c @@ -74,7 +74,7 @@ tcp_open(const char *name, char *suffix, struct stream **streamp) struct sockaddr_in sin; int fd, error; - error = tcp_open_active(suffix, 0, &sin, &fd); + error = inet_open_active(SOCK_STREAM, suffix, 0, &sin, &fd); if (fd >= 0) { return new_tcp_stream(name, fd, error, &sin, streamp); } else { @@ -103,7 +103,7 @@ ptcp_open(const char *name UNUSED, char *suffix, struct pstream **pstreamp) { int fd; - fd = tcp_open_passive(suffix, 0); + fd = inet_open_passive(SOCK_STREAM, suffix, 0); if (fd < 0) { return -fd; } else { diff --git a/lib/svec.c b/lib/svec.c index 81a36b57a..bc3df23d5 100644 --- a/lib/svec.c +++ b/lib/svec.c @@ -372,6 +372,22 @@ svec_join(const struct svec *svec, return ds_cstr(&ds); } +/* Breaks 's' into tokens at any character in 'delimiters', and appends each + * token to 'svec'. Empty tokens are not added. */ +void +svec_split(struct svec *svec, const char *s_, const char *delimiters) +{ + char *s = xstrdup(s_); + char *save_ptr = NULL; + char *token; + + for (token = strtok_r(s, delimiters, &save_ptr); token != NULL; + token = strtok_r(NULL, delimiters, &save_ptr)) { + svec_add(svec, token); + } + free(s); +} + const char * svec_back(const struct svec *svec) { diff --git a/lib/svec.h b/lib/svec.h index ff5619732..2a93139ad 100644 --- a/lib/svec.h +++ b/lib/svec.h @@ -53,6 +53,7 @@ void svec_swap(struct svec *a, struct svec *b); void svec_print(const struct svec *svec, const char *title); void svec_parse_words(struct svec *svec, const char *words); bool svec_equal(const struct svec *, const struct svec *); +void svec_split(struct svec *, const char *s, const char *delimiters); char *svec_join(const struct svec *, const char *delimiter, const char *terminator); const char *svec_back(const struct svec *); diff --git a/lib/timeval.c b/lib/timeval.c index 84abdfae4..5e4238758 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -43,8 +43,8 @@ static struct timeval now; /* Time at which to die with SIGALRM (if not TIME_MIN). */ static time_t deadline = TIME_MIN; -static void setup_timer(void); -static void setup_signal(int flags); +static void set_up_timer(void); +static void set_up_signal(int flags); static void sigalrm_handler(int); static void refresh_if_ticked(void); static time_t time_add(time_t, time_t); @@ -67,12 +67,12 @@ time_init(void) gettimeofday(&now, NULL); tick = false; - setup_signal(SA_RESTART); - setup_timer(); + set_up_signal(SA_RESTART); + set_up_timer(); } static void -setup_signal(int flags) +set_up_signal(int flags) { struct sigaction sa; @@ -100,7 +100,7 @@ setup_signal(int flags) void time_disable_restart(void) { - setup_signal(0); + set_up_signal(0); } /* Add SA_RESTART to the flags for SIGALRM, so that any system call that @@ -109,11 +109,11 @@ time_disable_restart(void) void time_enable_restart(void) { - setup_signal(SA_RESTART); + set_up_signal(SA_RESTART); } static void -setup_timer(void) +set_up_timer(void) { struct itimerval itimer; @@ -133,7 +133,7 @@ setup_timer(void) void time_postfork(void) { - setup_timer(); + set_up_timer(); } /* Forces a refresh of the current time from the kernel. It is not usually diff --git a/lib/unixctl.c b/lib/unixctl.c index 8565e5882..637843941 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -170,7 +170,7 @@ unixctl_command_reply(struct unixctl_conn *conn, * A program that (optionally) daemonizes itself should call this function * *after* daemonization, so that the socket name contains the pid of the * daemon instead of the pid of the program that exited. (Otherwise, - * "ovs-appctl --target <program>.pid" will fail.) + * "ovs-appctl --target=<program>" will fail.) * * Returns 0 if successful, otherwise a positive errno value. If successful, * sets '*serverp' to the new unixctl_server, otherwise to NULL. */ diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index 2452bcea5..58c54f877 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -288,7 +288,7 @@ ssl_open(const char *name, char *suffix, struct vconn **vconnp) return error; } - error = tcp_open_active(suffix, OFP_SSL_PORT, &sin, &fd); + error = inet_open_active(SOCK_STREAM, suffix, OFP_SSL_PORT, &sin, &fd); if (fd >= 0) { int state = error ? STATE_TCP_CONNECTING : STATE_SSL_CONNECTING; return new_ssl_vconn(name, fd, CLIENT, state, &sin, vconnp); @@ -776,7 +776,7 @@ pssl_open(const char *name, char *suffix, struct pvconn **pvconnp) return retval; } - fd = tcp_open_passive(suffix, OFP_SSL_PORT); + fd = inet_open_passive(SOCK_STREAM, suffix, OFP_SSL_PORT); if (fd < 0) { return -fd; } diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c index b4e523435..aac716623 100644 --- a/lib/vconn-tcp.c +++ b/lib/vconn-tcp.c @@ -75,7 +75,7 @@ tcp_open(const char *name, char *suffix, struct vconn **vconnp) struct sockaddr_in sin; int fd, error; - error = tcp_open_active(suffix, OFP_TCP_PORT, &sin, &fd); + error = inet_open_active(SOCK_STREAM, suffix, OFP_TCP_PORT, &sin, &fd); if (fd >= 0) { return new_tcp_vconn(name, fd, error, &sin, vconnp); } else { @@ -104,7 +104,7 @@ ptcp_open(const char *name UNUSED, char *suffix, struct pvconn **pvconnp) { int fd; - fd = tcp_open_passive(suffix, OFP_TCP_PORT); + fd = inet_open_passive(SOCK_STREAM, suffix, OFP_TCP_PORT); if (fd < 0) { return -fd; } else { diff --git a/lib/vconn.c b/lib/vconn.c index 3cd294874..b11650fbc 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -1042,7 +1042,7 @@ check_ofp_message(const struct ofp_header *msg, uint8_t type, size_t size) if (got_size != size) { char *type_name = ofp_message_type_to_string(type); VLOG_WARN_RL(&bad_ofmsg_rl, - "received %s message of length %"PRIu16" (expected %zu)", + "received %s message of length %zu (expected %zu)", type_name, got_size, size); free(type_name); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH); @@ -1077,7 +1077,7 @@ check_ofp_message_array(const struct ofp_header *msg, uint8_t type, got_size = ntohs(msg->length); if (got_size < min_size) { char *type_name = ofp_message_type_to_string(type); - VLOG_WARN_RL(&bad_ofmsg_rl, "received %s message of length %"PRIu16" " + VLOG_WARN_RL(&bad_ofmsg_rl, "received %s message of length %zu " "(expected at least %zu)", type_name, got_size, min_size); free(type_name); @@ -1086,7 +1086,7 @@ check_ofp_message_array(const struct ofp_header *msg, uint8_t type, if ((got_size - min_size) % array_elt_size) { char *type_name = ofp_message_type_to_string(type); VLOG_WARN_RL(&bad_ofmsg_rl, - "received %s message of bad length %"PRIu16": the " + "received %s message of bad length %zu: the " "excess over %zu (%zu) is not evenly divisible by %zu " "(remainder is %zu)", type_name, got_size, min_size, got_size - min_size, @@ -1119,13 +1119,13 @@ check_ofp_packet_out(const struct ofp_header *oh, struct ofpbuf *data, actions_len = ntohs(opo->actions_len); if (actions_len > extra) { - VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %zu bytes of actions " + VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions " "but message has room for only %zu bytes", actions_len, extra); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH); } if (actions_len % sizeof(union ofp_action)) { - VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %zu bytes of actions, " + VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions, " "which is not a multiple of %zu", actions_len, sizeof(union ofp_action)); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH); @@ -1282,7 +1282,8 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports) break; default: - VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16, a->type); + VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16, + ntohs(a->type)); return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); } @@ -1312,7 +1313,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions, if (n_slots > slots_left) { VLOG_DBG_RL(&bad_ofmsg_rl, - "action requires %u slots but only %td remain", + "action requires %u slots but only %u remain", n_slots, slots_left); return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } @@ -1360,7 +1361,7 @@ normalize_match(struct ofp_match *m) if (wc & OFPFW_DL_TYPE) { m->dl_type = 0; - /* Can't sensibly m on network or transport headers if the + /* Can't sensibly match on network or transport headers if the * data link type is unknown. */ wc |= OFPFW_NW | OFPFW_TP; m->nw_src = m->nw_dst = m->nw_proto = 0; @@ -1369,7 +1370,7 @@ normalize_match(struct ofp_match *m) if (wc & OFPFW_NW_PROTO) { m->nw_proto = 0; - /* Can't sensibly m on transport headers if the network + /* Can't sensibly match on transport headers if the network * protocol is unknown. */ wc |= OFPFW_TP; m->tp_src = m->tp_dst = 0; @@ -1384,7 +1385,7 @@ normalize_match(struct ofp_match *m) } } else { /* Transport layer fields will always be extracted as zeros, so we - * can do an exact-m on those values. */ + * can do an exact-match on those values. */ wc &= ~OFPFW_TP; m->tp_src = m->tp_dst = 0; } @@ -1396,7 +1397,7 @@ normalize_match(struct ofp_match *m) } } else { /* Network and transport layer fields will always be extracted as - * zeros, so we can do an exact-m on those values. */ + * zeros, so we can do an exact-match on those values. */ wc &= ~(OFPFW_NW | OFPFW_TP); m->nw_proto = m->nw_src = m->nw_dst = 0; m->tp_src = m->tp_dst = 0; diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 2f056c855..9a9ea065c 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -21,6 +21,7 @@ VLOG_MODULE(bridge) VLOG_MODULE(chain) VLOG_MODULE(cfg) VLOG_MODULE(cfg_mod) +VLOG_MODULE(collectors) VLOG_MODULE(controller) VLOG_MODULE(coverage) VLOG_MODULE(ctlpath) diff --git a/lib/vlog-unixctl.man b/lib/vlog-unixctl.man index 5c79875fc..86eece3b7 100644 --- a/lib/vlog-unixctl.man +++ b/lib/vlog-unixctl.man @@ -7,7 +7,7 @@ Sets the logging level for \fImodule\fR in \fIfacility\fR to .RS .IP \(bu \fImodule\fR may be any valid module name (as displayed by the -\fB--list\fR action on \fBovs-appctl\fR(8)), or the special name +\fB--list\fR action on \fBovs\-appctl\fR(8)), or the special name \fBANY\fR to set the logging levels for all modules. . .IP \(bu @@ -26,7 +26,7 @@ logged. If it is omitted, \fIlevel\fR defaults to \fBdbg\fR. .RE .IP "\fBvlog/set PATTERN:\fIfacility\fB:\fIpattern\fR" Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Refer to -\fBovs-appctl\fR(8) for a description of the valid syntax for \fIpattern\fR. +\fBovs\-appctl\fR(8) for a description of the valid syntax for \fIpattern\fR. . .IP "\fBvlog/list\fR" Lists the supported logging modules and their current levels. diff --git a/lib/vlog.man b/lib/vlog.man index 0bd8a26e8..882793164 100644 --- a/lib/vlog.man +++ b/lib/vlog.man @@ -7,7 +7,7 @@ Sets the logging level for \fImodule\fR in \fIfacility\fR to .RS .IP \(bu \fImodule\fR may be any valid module name (as displayed by the -\fB--list\fR action on \fBovs-appctl\fR(8)), or the special name +\fB--list\fR action on \fBovs\-appctl\fR(8)), or the special name \fBANY\fR to set the logging levels for all modules. .IP \(bu @@ -35,7 +35,7 @@ Sets the maximum logging verbosity level, equivalent to .TP \fB-vPATTERN:\fIfacility\fB:\fIpattern\fR, \fB--verbose=PATTERN:\fIfacility\fB:\fIpattern\fR Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Refer to -\fBovs-appctl\fR(8) for a description of the valid syntax for \fIpattern\fR. +\fBovs\-appctl\fR(8) for a description of the valid syntax for \fIpattern\fR. .TP \fB--log-file\fR[\fB=\fIfile\fR] |