X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fbfd.c;h=8b5daffad3958e647ceaa98aea45f639cbf05636;hb=HEAD;hp=d83d198a173d47749ef5dc60cb96c6219596a887;hpb=5383f2c2fe32315615e04bf411d2fd1953d59f31;p=cascardo%2Fovs.git diff --git a/lib/bfd.c b/lib/bfd.c index d83d198a1..8b5daffad 100644 --- 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. @@ -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" @@ -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; }