netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / lib / bfd.c
index d83d198..8b5daff 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, 2014 Nicira, Inc.
+/* Copyright (c) 2013, 2014, 2015, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <arpa/inet.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <sys/socket.h>
 
 #include "byte-order.h"
 #include "connectivity.h"
 #include "csum.h"
+#include "dp-packet.h"
 #include "dpif.h"
 #include "dynamic-string.h"
 #include "flow.h"
@@ -43,7 +45,7 @@
 #include "unaligned.h"
 #include "unixctl.h"
 #include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(bfd);
 
@@ -168,8 +170,10 @@ struct bfd {
 
     uint32_t rmt_disc;            /* bfd.RemoteDiscr. */
 
-    uint8_t eth_dst[ETH_ADDR_LEN];/* Ethernet destination address. */
-    bool eth_dst_set;             /* 'eth_dst' set through database. */
+    struct eth_addr local_eth_src; /* Local eth src address. */
+    struct eth_addr local_eth_dst; /* Local eth dst address. */
+
+    struct eth_addr rmt_eth_dst;   /* Remote eth dst address. */
 
     ovs_be32 ip_src;              /* IPv4 source address. */
     ovs_be32 ip_dst;              /* IPv4 destination address. */
@@ -317,14 +321,21 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap)
     smap_add(smap, "state", bfd_state_str(bfd->state));
     smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag));
     smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
-
-    if (bfd->state != STATE_DOWN) {
-        smap_add(smap, "remote_state", bfd_state_str(bfd->rmt_state));
-        smap_add(smap, "remote_diagnostic", bfd_diag_str(bfd->rmt_diag));
-    }
+    smap_add(smap, "remote_state", bfd_state_str(bfd->rmt_state));
+    smap_add(smap, "remote_diagnostic", bfd_diag_str(bfd->rmt_diag));
     ovs_mutex_unlock(&mutex);
 }
 
+void
+bfd_init(void)
+{
+    unixctl_command_register("bfd/show", "[interface]", 0, 1,
+                             bfd_unixctl_show, NULL);
+    unixctl_command_register("bfd/set-forwarding",
+                             "[interface] normal|false|true", 1, 2,
+                             bfd_unixctl_set_forwarding_override, NULL);
+}
+
 /* Initializes, destroys, or reconfigures the BFD session 'bfd' (named 'name'),
  * according to the database configuration contained in 'cfg'.  Takes ownership
  * of 'bfd', which may be NULL.  Returns a BFD object which may be used as a
@@ -334,8 +345,7 @@ struct bfd *
 bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
               struct netdev *netdev) OVS_EXCLUDED(mutex)
 {
-    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
-    static atomic_uint16_t udp_src = ATOMIC_VAR_INIT(0);
+    static atomic_count udp_src = ATOMIC_COUNT_INIT(0);
 
     int decay_min_rx;
     long long int min_tx, min_rx;
@@ -344,16 +354,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     bool cpath_down, forwarding_if_rx;
     const char *hwaddr, *ip_src, *ip_dst;
     struct in_addr in_addr;
-    uint8_t ea[ETH_ADDR_LEN];
-
-    if (ovsthread_once_start(&once)) {
-        unixctl_command_register("bfd/show", "[interface]", 0, 1,
-                                 bfd_unixctl_show, NULL);
-        unixctl_command_register("bfd/set-forwarding",
-                                 "[interface] normal|false|true", 1, 2,
-                                 bfd_unixctl_set_forwarding_override, NULL);
-        ovsthread_once_done(&once);
-    }
+    struct eth_addr ea;
 
     if (!cfg || !smap_get_bool(cfg, "enable", false)) {
         bfd_unref(bfd);
@@ -382,20 +383,17 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
          * UDP source port number MUST be used for all BFD Control packets
          * associated with a particular session.  The source port number SHOULD
          * be unique among all BFD sessions on the system. */
-        atomic_add(&udp_src, 1, &bfd->udp_src);
-        bfd->udp_src = (bfd->udp_src % 16384) + 49152;
+        bfd->udp_src = (atomic_count_inc(&udp_src) % 16384) + 49152;
 
         bfd_set_state(bfd, STATE_DOWN, DIAG_NONE);
 
-        memcpy(bfd->eth_dst, eth_addr_bfd, ETH_ADDR_LEN);
-
         bfd_status_changed(bfd);
     }
 
-    atomic_store(&bfd->check_tnl_key,
-                 smap_get_bool(cfg, "check_tnl_key", false));
+    atomic_store_relaxed(&bfd->check_tnl_key,
+                         smap_get_bool(cfg, "check_tnl_key", false));
     min_tx = smap_get_int(cfg, "min_tx", 100);
-    min_tx = MAX(min_tx, 100);
+    min_tx = MAX(min_tx, 1);
     if (bfd->cfg_min_tx != min_tx) {
         bfd->cfg_min_tx = min_tx;
         if (bfd->state != STATE_UP
@@ -406,7 +404,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     }
 
     min_rx = smap_get_int(cfg, "min_rx", 1000);
-    min_rx = MAX(min_rx, 100);
+    min_rx = MAX(min_rx, 1);
     if (bfd->cfg_min_rx != min_rx) {
         bfd->cfg_min_rx = min_rx;
         if (bfd->state != STATE_UP
@@ -439,27 +437,39 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
         need_poll = true;
     }
 
-    hwaddr = smap_get(cfg, "bfd_dst_mac");
-    if (hwaddr && eth_addr_from_string(hwaddr, ea) && !eth_addr_is_zero(ea)) {
-        memcpy(bfd->eth_dst, ea, ETH_ADDR_LEN);
-        bfd->eth_dst_set = true;
-    } else if (bfd->eth_dst_set) {
-        memcpy(bfd->eth_dst, eth_addr_bfd, ETH_ADDR_LEN);
-        bfd->eth_dst_set = false;
+    hwaddr = smap_get(cfg, "bfd_local_src_mac");
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->local_eth_src = ea;
+    } else {
+        bfd->local_eth_src = eth_addr_zero;
+    }
+
+    hwaddr = smap_get(cfg, "bfd_local_dst_mac");
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->local_eth_dst = ea;
+    } else {
+        bfd->local_eth_dst = eth_addr_zero;
+    }
+
+    hwaddr = smap_get(cfg, "bfd_remote_dst_mac");
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->rmt_eth_dst = ea;
+    } else {
+        bfd->rmt_eth_dst = eth_addr_zero;
     }
 
     ip_src = smap_get(cfg, "bfd_src_ip");
     if (ip_src && bfd_lookup_ip(ip_src, &in_addr)) {
         memcpy(&bfd->ip_src, &in_addr, sizeof in_addr);
     } else {
-        bfd->ip_src = htonl(0xA9FE0100); /* 169.254.1.0. */
+        bfd->ip_src = htonl(0xA9FE0101); /* 169.254.1.1. */
     }
 
     ip_dst = smap_get(cfg, "bfd_dst_ip");
     if (ip_dst && bfd_lookup_ip(ip_dst, &in_addr)) {
         memcpy(&bfd->ip_dst, &in_addr, sizeof in_addr);
     } else {
-        bfd->ip_dst = htonl(0xA9FE0101); /* 169.254.1.1. */
+        bfd->ip_dst = htonl(0xA9FE0100); /* 169.254.1.0. */
     }
 
     forwarding_if_rx = smap_get_bool(cfg, "forwarding_if_rx", false);
@@ -492,7 +502,7 @@ bfd_ref(const struct bfd *bfd_)
 void
 bfd_unref(struct bfd *bfd) OVS_EXCLUDED(mutex)
 {
-    if (bfd && ovs_refcount_unref(&bfd->ref_cnt) == 1) {
+    if (bfd && ovs_refcount_unref_relaxed(&bfd->ref_cnt) == 1) {
         ovs_mutex_lock(&mutex);
         bfd_status_changed(bfd);
         hmap_remove(all_bfds, &bfd->node);
@@ -503,10 +513,12 @@ bfd_unref(struct bfd *bfd) OVS_EXCLUDED(mutex)
     }
 }
 
-void
+long long int
 bfd_wait(const struct bfd *bfd) OVS_EXCLUDED(mutex)
 {
-    poll_timer_wait_until(bfd_wake_time(bfd));
+    long long int wake_time = bfd_wake_time(bfd);
+    poll_timer_wait_until(wake_time);
+    return wake_time;
 }
 
 /* Returns the next wake up time. */
@@ -573,8 +585,8 @@ bfd_should_send_packet(const struct bfd *bfd) OVS_EXCLUDED(mutex)
 }
 
 void
-bfd_put_packet(struct bfd *bfd, struct ofpbuf *p,
-               uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
+bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
+               const struct eth_addr eth_src) OVS_EXCLUDED(mutex)
 {
     long long int min_tx, min_rx;
     struct udp_header *udp;
@@ -597,13 +609,15 @@ bfd_put_packet(struct bfd *bfd, struct ofpbuf *p,
      * set. */
     ovs_assert(!(bfd->flags & FLAG_POLL) || !(bfd->flags & FLAG_FINAL));
 
-    ofpbuf_reserve(p, 2); /* Properly align after the ethernet header. */
-    eth = ofpbuf_put_uninit(p, sizeof *eth);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
-    memcpy(eth->eth_dst, bfd->eth_dst, ETH_ADDR_LEN);
+    dp_packet_reserve(p, 2); /* Properly align after the ethernet header. */
+    eth = dp_packet_put_uninit(p, sizeof *eth);
+    eth->eth_src = eth_addr_is_zero(bfd->local_eth_src)
+        ? eth_src : bfd->local_eth_src;
+    eth->eth_dst = eth_addr_is_zero(bfd->local_eth_dst)
+        ? eth_addr_bfd : bfd->local_eth_dst;
     eth->eth_type = htons(ETH_TYPE_IP);
 
-    ip = ofpbuf_put_zeros(p, sizeof *ip);
+    ip = dp_packet_put_zeros(p, sizeof *ip);
     ip->ip_ihl_ver = IP_IHL_VER(5, 4);
     ip->ip_tot_len = htons(sizeof *ip + sizeof *udp + sizeof *msg);
     ip->ip_ttl = MAXTTL;
@@ -613,12 +627,12 @@ bfd_put_packet(struct bfd *bfd, struct ofpbuf *p,
     put_16aligned_be32(&ip->ip_dst, bfd->ip_dst);
     ip->ip_csum = csum(ip, sizeof *ip);
 
-    udp = ofpbuf_put_zeros(p, sizeof *udp);
+    udp = dp_packet_put_zeros(p, sizeof *udp);
     udp->udp_src = htons(bfd->udp_src);
     udp->udp_dst = htons(BFD_DEST_PORT);
     udp->udp_len = htons(sizeof *udp + sizeof *msg);
 
-    msg = ofpbuf_put_uninit(p, sizeof *msg);
+    msg = dp_packet_put_uninit(p, sizeof *msg);
     msg->vers_diag = (BFD_VERSION << 5) | bfd->diag;
     msg->flags = (bfd->state & STATE_MASK) | bfd->flags;
 
@@ -653,36 +667,45 @@ bfd_should_process_flow(const struct bfd *bfd_, const struct flow *flow,
                         struct flow_wildcards *wc)
 {
     struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
-    bool check_tnl_key;
 
-    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
-    if (bfd->eth_dst_set && memcmp(bfd->eth_dst, flow->dl_dst, ETH_ADDR_LEN)) {
-        return false;
-    }
+    if (!eth_addr_is_zero(bfd->rmt_eth_dst)) {
+        memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
 
-    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
-    memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+        if (!eth_addr_equals(bfd->rmt_eth_dst, flow->dl_dst)) {
+            return false;
+        }
+    }
 
-    atomic_read(&bfd->check_tnl_key, &check_tnl_key);
-    if (check_tnl_key) {
-        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+        if (flow->nw_proto == IPPROTO_UDP) {
+            memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+            if (flow->tp_dst == htons(BFD_DEST_PORT)) {
+                bool check_tnl_key;
+
+                atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key);
+                if (check_tnl_key) {
+                    memset(&wc->masks.tunnel.tun_id, 0xff,
+                           sizeof wc->masks.tunnel.tun_id);
+                    return flow->tunnel.tun_id == htonll(0);
+                }
+                return true;
+            }
+        }
     }
-    return (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IPPROTO_UDP
-            && flow->tp_dst == htons(BFD_DEST_PORT)
-            && (!check_tnl_key || flow->tunnel.tun_id == htonll(0)));
+    return false;
 }
 
 void
 bfd_process_packet(struct bfd *bfd, const struct flow *flow,
-                   const struct ofpbuf *p) OVS_EXCLUDED(mutex)
+                   const struct dp_packet *p) OVS_EXCLUDED(mutex)
 {
     uint32_t rmt_min_rx, pkt_your_disc;
     enum state rmt_state;
     enum flags flags;
     uint8_t version;
     struct msg *msg;
-    const uint8_t *l7 = ofpbuf_get_udp_payload(p);
+    const uint8_t *l7 = dp_packet_get_udp_payload(p);
 
     if (!l7) {
         return; /* No UDP payload. */
@@ -701,11 +724,11 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
         goto out;
     }
 
-    msg = ofpbuf_at(p, l7 - (uint8_t *)ofpbuf_data(p), BFD_PACKET_LEN);
+    msg = dp_packet_at(p, l7 - (uint8_t *)dp_packet_data(p), BFD_PACKET_LEN);
     if (!msg) {
         VLOG_INFO_RL(&rl, "%s: Received too-short BFD control message (only "
                      "%"PRIdPTR" bytes long, at least %d required).",
-                     bfd->name, (uint8_t *) ofpbuf_tail(p) - l7,
+                     bfd->name, (uint8_t *) dp_packet_tail(p) - l7,
                      BFD_PACKET_LEN);
         goto out;
     }
@@ -714,7 +737,7 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
      * If the Length field is greater than the payload of the encapsulating
      * protocol, the packet MUST be discarded.
      *
-     * Note that we make this check implicity.  Above we use ofpbuf_at() to
+     * Note that we make this check implicitly.  Above we use dp_packet_at() to
      * ensure that there are at least BFD_PACKET_LEN bytes in the payload of
      * the encapsulating protocol.  Below we require msg->length to be exactly
      * BFD_PACKET_LEN bytes. */
@@ -916,7 +939,7 @@ bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
 static bool
 bfd_lookup_ip(const char *host_name, struct in_addr *addr)
 {
-    if (!inet_pton(AF_INET, host_name, addr)) {
+    if (!ip_parse(host_name, &addr->s_addr)) {
         VLOG_ERR_RL(&rl, "\"%s\" is not a valid IP address", host_name);
         return false;
     }
@@ -1050,7 +1073,7 @@ log_msg(enum vlog_level level, const struct msg *p, const char *message,
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
 
-    if (vlog_should_drop(THIS_MODULE, level, &rl)) {
+    if (vlog_should_drop(&this_module, level, &rl)) {
         return;
     }