X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fbfd.c;h=8b5daffad3958e647ceaa98aea45f639cbf05636;hb=HEAD;hp=a8c229415aecd5c002d0798439d7382b7a8afadf;hpb=dfe37e6abd276de01f686bbdf28cbf48e92cd1dc;p=cascardo%2Fovs.git diff --git a/lib/bfd.c b/lib/bfd.c index a8c229415..8b5daffad 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013 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. @@ -19,10 +19,12 @@ #include #include #include +#include #include "byte-order.h" #include "connectivity.h" #include "csum.h" +#include "dp-packet.h" #include "dpif.h" #include "dynamic-string.h" #include "flow.h" @@ -30,7 +32,6 @@ #include "hmap.h" #include "list.h" #include "netdev.h" -#include "netlink.h" #include "odp-util.h" #include "ofpbuf.h" #include "ovs-thread.h" @@ -44,7 +45,7 @@ #include "unaligned.h" #include "unixctl.h" #include "util.h" -#include "vlog.h" +#include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(bfd); @@ -169,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. */ @@ -204,6 +207,12 @@ struct bfd { bool forwarding_if_rx; long long int forwarding_if_rx_detect_time; + /* When 'bfd->forwarding_if_rx' is set, at least one bfd control packet + * is required to be received every 100 * bfd->cfg_min_rx. If bfd + * control packet is not received within this interval, even if data + * packets are received, the bfd->forwarding will still be false. */ + long long int demand_rx_bfd_time; + /* BFD decay related variables. */ bool in_decay; /* True when bfd is in decay. */ int decay_min_rx; /* min_rx is set to decay_min_rx when */ @@ -214,6 +223,10 @@ struct bfd { long long int decay_detect_time; /* Decay detection time. */ uint64_t flap_count; /* Counts bfd forwarding flaps. */ + + /* True when the variables returned by bfd_get_status() are changed + * since last check. */ + bool status_changed; }; static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; @@ -241,6 +254,7 @@ static void bfd_put_details(struct ds *, const struct bfd *) static uint64_t bfd_rx_packets(const struct bfd *) OVS_REQUIRES(mutex); static void bfd_try_decay(struct bfd *) OVS_REQUIRES(mutex); static void bfd_decay_update(struct bfd *) OVS_REQUIRES(mutex); +static void bfd_status_changed(struct bfd *) OVS_REQUIRES(mutex); static void bfd_forwarding_if_rx_update(struct bfd *) OVS_REQUIRES(mutex); static void bfd_unixctl_show(struct unixctl_conn *, int argc, @@ -280,6 +294,20 @@ bfd_account_rx(struct bfd *bfd, const struct dpif_flow_stats *stats) } } +/* Returns and resets the 'bfd->status_changed'. */ +bool +bfd_check_status_change(struct bfd *bfd) OVS_EXCLUDED(mutex) +{ + bool ret; + + ovs_mutex_lock(&mutex); + ret = bfd->status_changed; + bfd->status_changed = false; + ovs_mutex_unlock(&mutex); + + return ret; +} + /* Returns a 'smap' of key value pairs representing the status of 'bfd' * intended for the OVS database. */ void @@ -293,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 @@ -310,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; @@ -320,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); @@ -358,18 +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 @@ -380,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 @@ -413,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); @@ -466,21 +502,23 @@ 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); netdev_close(bfd->netdev); - ovs_refcount_destroy(&bfd->ref_cnt); free(bfd->name); free(bfd); ovs_mutex_unlock(&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. */ @@ -547,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; @@ -571,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; @@ -587,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; @@ -627,35 +667,49 @@ 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 = dp_packet_get_udp_payload(p); + + if (!l7) { + return; /* No UDP payload. */ + } /* This function is designed to follow section RFC 5880 6.8.6 closely. */ @@ -670,11 +724,11 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow, goto out; } - msg = ofpbuf_at(p, (uint8_t *)p->l7 - (uint8_t *)p->data, 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) - (uint8_t *) p->l7, + bfd->name, (uint8_t *) dp_packet_tail(p) - l7, BFD_PACKET_LEN); goto out; } @@ -683,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. */ @@ -746,7 +800,7 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow, } if (bfd->rmt_state != rmt_state) { - seq_change(connectivity_seq_get()); + bfd_status_changed(bfd); } bfd->rmt_disc = ntohl(msg->my_disc); @@ -819,6 +873,10 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow, } /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */ + if (bfd->forwarding_if_rx) { + bfd->demand_rx_bfd_time = time_msec() + 100 * bfd->cfg_min_rx; + } + out: bfd_forwarding__(bfd); ovs_mutex_unlock(&mutex); @@ -854,22 +912,25 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev) static bool bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex) { - long long int time; + long long int now = time_msec(); + bool forwarding_if_rx; bool last_forwarding = bfd->last_forwarding; if (bfd->forwarding_override != -1) { return bfd->forwarding_override == 1; } - time = bfd->forwarding_if_rx_detect_time; - bfd->last_forwarding = (bfd->state == STATE_UP - || (bfd->forwarding_if_rx && time > time_msec())) - && bfd->rmt_diag != DIAG_PATH_DOWN - && bfd->rmt_diag != DIAG_CPATH_DOWN - && bfd->rmt_diag != DIAG_RCPATH_DOWN; + forwarding_if_rx = bfd->forwarding_if_rx + && bfd->forwarding_if_rx_detect_time > now + && bfd->demand_rx_bfd_time > now; + + bfd->last_forwarding = (bfd->state == STATE_UP || forwarding_if_rx) + && bfd->rmt_diag != DIAG_PATH_DOWN + && bfd->rmt_diag != DIAG_CPATH_DOWN + && bfd->rmt_diag != DIAG_RCPATH_DOWN; if (bfd->last_forwarding != last_forwarding) { bfd->flap_count++; - seq_change(connectivity_seq_get()); + bfd_status_changed(bfd); } return bfd->last_forwarding; } @@ -878,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_aton(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; } @@ -1012,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; } @@ -1082,7 +1143,7 @@ bfd_set_state(struct bfd *bfd, enum state state, enum diag diag) bfd_decay_update(bfd); } - seq_change(connectivity_seq_get()); + bfd_status_changed(bfd); } } @@ -1129,6 +1190,14 @@ bfd_decay_update(struct bfd * bfd) OVS_REQUIRES(mutex) bfd->decay_detect_time = MAX(bfd->decay_min_rx, 2000) + time_msec(); } +/* Records the status change and changes the global connectivity seq. */ +static void +bfd_status_changed(struct bfd *bfd) OVS_REQUIRES(mutex) +{ + seq_change(connectivity_seq_get()); + bfd->status_changed = true; +} + static void bfd_forwarding_if_rx_update(struct bfd *bfd) OVS_REQUIRES(mutex) { @@ -1276,9 +1345,11 @@ bfd_unixctl_set_forwarding_override(struct unixctl_conn *conn, int argc, goto out; } bfd->forwarding_override = forwarding_override; + bfd_status_changed(bfd); } else { HMAP_FOR_EACH (bfd, node, all_bfds) { bfd->forwarding_override = forwarding_override; + bfd_status_changed(bfd); } }