On Tue, Aug 2, 2022 at 4:04 PM Toms Atteka <[email protected]> wrote:
>
> Added config options for source and destination IPv6 addresses to
> BFD packets. IPv6 address presence overrides IPv4 address and
> packets are crafted as IPv6.
>
> Added IP address values to status to ease setting up IP addresses.
>
> Signed-off-by: Toms Atteka <[email protected]>
> ---
>  lib/bfd.c            | 119 ++++++++++++++++++++++++++++++++++++++-----
>  tests/bfd.at         |  30 +++++++++++
>  vswitchd/vswitch.xml |  10 ++++
>  3 files changed, 147 insertions(+), 12 deletions(-)
>
> diff --git a/lib/bfd.c b/lib/bfd.c
> index 9698576d0..f9f359e99 100644
> --- a/lib/bfd.c
> +++ b/lib/bfd.c
> @@ -187,6 +187,9 @@ struct bfd {
>      ovs_be32 ip_src;              /* IPv4 source address. */
>      ovs_be32 ip_dst;              /* IPv4 destination address. */
>
> +    struct in6_addr ipv6_src;              /* IPv6 source address. */
> +    struct in6_addr ipv6_dst;              /* IPv6 destination address. */

Could we just change the IP members to in6_addr and then use the
in6_addr_*_ipv4() functions? Are separate members required here?

Nit: The comments here could be aligned.

> +
>      uint16_t udp_src;             /* UDP source port. */
>
>      /* All timers in milliseconds. */
> @@ -244,10 +247,14 @@ static struct hmap *const all_bfds 
> OVS_GUARDED_BY(mutex) = &all_bfds__;
>
>  static void bfd_lookup_ip(const char *host_name, ovs_be32 def, ovs_be32 *ip)
>      OVS_REQUIRES(mutex);
> +static void bfd_lookup_ipv6(const char *host_name, struct in6_addr *ipv6)
> +    OVS_REQUIRES(mutex);
>  static bool bfd_forwarding__(struct bfd *) OVS_REQUIRES(mutex);
>  static bool bfd_in_poll(const struct bfd *) OVS_REQUIRES(mutex);
>  static void bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex);
>  static const char *bfd_diag_str(enum diag) OVS_REQUIRES(mutex);
> +static const char *bfd_ip_str(ovs_be32 ip) OVS_REQUIRES(mutex);
> +static const char *bfd_ipv6_str(struct in6_addr ipv6) OVS_REQUIRES(mutex);
>  static const char *bfd_state_str(enum state) OVS_REQUIRES(mutex);
>  static long long int bfd_min_tx(const struct bfd *) OVS_REQUIRES(mutex);
>  static long long int bfd_tx_interval(const struct bfd *)
> @@ -332,6 +339,18 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap)
>      smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
>      smap_add(smap, "remote_state", bfd_state_str(bfd->rmt_state));
>      smap_add(smap, "remote_diagnostic", bfd_diag_str(bfd->rmt_diag));
> +    if (bfd->ip_src) {
> +        smap_add(smap, "bfd_src_ip", bfd_ip_str(bfd->ip_src));
> +    }
> +    if (bfd->ip_dst) {
> +        smap_add(smap, "bfd_dst_ip", bfd_ip_str(bfd->ip_dst));
> +    }
> +    if (ipv6_addr_is_set(&bfd->ipv6_src)) {
> +       smap_add(smap, "bfd_src_ipv6", bfd_ipv6_str(bfd->ipv6_src));
> +    }
> +    if (ipv6_addr_is_set(&bfd->ipv6_dst)) {
> +        smap_add(smap, "bfd_dst_ipv6", bfd_ipv6_str(bfd->ipv6_dst));
> +    }
>      ovs_mutex_unlock(&mutex);
>  }
>
> @@ -465,6 +484,10 @@ bfd_configure(struct bfd *bfd, const char *name, const 
> struct smap *cfg,
>      bfd_lookup_ip(smap_get_def(cfg, "bfd_dst_ip", ""),
>                    htonl(BFD_DEFAULT_DST_IP), &bfd->ip_dst);
>
> +    bfd_lookup_ipv6(smap_get_def(cfg, "bfd_src_ipv6", ""), &bfd->ipv6_src);
> +    bfd_lookup_ipv6(smap_get_def(cfg, "bfd_dst_ipv6", ""), &bfd->ipv6_dst);

Other similar options in OVS use the same key for ipv4 and ipv6. For
example, the remote_ip field in netdev-vport.c. Can we do the same
thing here?

> +
> +

Nit: Extra space

>      forwarding_if_rx = smap_get_bool(cfg, "forwarding_if_rx", false);
>      if (bfd->forwarding_if_rx != forwarding_if_rx) {
>          bfd->forwarding_if_rx = forwarding_if_rx;
> @@ -588,6 +611,7 @@ bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
>      struct udp_header *udp;
>      struct eth_header *eth;
>      struct ip_header *ip;
> +    struct ovs_16aligned_ip6_hdr *ip6;
>      struct msg *msg;
>
>      ovs_mutex_lock(&mutex);
> @@ -611,23 +635,40 @@ bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
>          ? 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 = 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;
> -    ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
> -    ip->ip_proto = IPPROTO_UDP;
> -    put_16aligned_be32(&ip->ip_src, bfd->ip_src);
> -    put_16aligned_be32(&ip->ip_dst, bfd->ip_dst);
> -    /* Checksum has already been zeroed by put_zeros call. */
> -    ip->ip_csum = csum(ip, sizeof *ip);
> +
> +    if (ipv6_addr_is_set(&bfd->ipv6_src)) {
> +        eth->eth_type = htons(ETH_TYPE_IPV6);
> +
> +        ip6 = dp_packet_put_zeros(p, sizeof *ip6);
> +
> +        ip6->ip6_vfc = 0x60;
> +        ip6->ip6_hlim = MAXTTL;
> +        ip6->ip6_nxt = IPPROTO_UDP;
> +        ip6->ip6_plen = htons(sizeof *udp + sizeof *msg);
> +
> +        memcpy(&ip6->ip6_src, &bfd->ipv6_src, sizeof(bfd->ipv6_src));
> +        memcpy(&ip6->ip6_dst, &bfd->ipv6_dst, sizeof(bfd->ipv6_dst));
> +
> +    } else {
> +        eth->eth_type = htons(ETH_TYPE_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;
> +        ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
> +        ip->ip_proto = IPPROTO_UDP;
> +        put_16aligned_be32(&ip->ip_src, bfd->ip_src);
> +        put_16aligned_be32(&ip->ip_dst, bfd->ip_dst);
> +        /* Checksum has already been zeroed by put_zeros call. */
> +        ip->ip_csum = csum(ip, sizeof *ip);
> +    }
>
>      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);
> +    udp->udp_csum = htons(0xffff);

This looks odd to me. Before the checksum was set to zero indicating
no checksum, which is only valid for IPv4. But isn't an actual
checksum required for IPv6?

I actually haven't actually tested this, but it does apply cleanly.
Let me know if I'm missing something on the checksum.


Thanks,
M

>
>      msg = dp_packet_put_uninit(p, sizeof *msg);
>      msg->vers_diag = (BFD_VERSION << 5) | bfd->diag;
> @@ -674,6 +715,27 @@ bfd_should_process_flow(const struct bfd *bfd_, const 
> struct flow *flow,
>          }
>      }
>
> +    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
> +        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> +        if (flow->nw_proto == IPPROTO_UDP
> +            && !(flow->nw_frag & FLOW_NW_FRAG_LATER)
> +            && tp_dst_equals(flow, BFD_DEST_PORT, wc)
> +            && ipv6_addr_equals(&bfd->ipv6_src, &flow->ipv6_dst)) {
> +
> +            memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
> +
> +            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;
> +        }
> +    }
> +
>      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
> @@ -958,6 +1020,17 @@ bfd_lookup_ip(const char *host_name, ovs_be32 def, 
> ovs_be32 *addr)
>      *addr = def;
>  }
>
> +static void
> +bfd_lookup_ipv6(const char *host_name, struct in6_addr *addr)
> +{
> +    if (host_name[0]) {
> +        if (ipv6_parse(host_name, addr)) {
> +            return;
> +        }
> +        VLOG_ERR_RL(&rl, "\"%s\" is not a valid IPv6 address", host_name);
> +    }
> +}
> +
>  static bool
>  bfd_in_poll(const struct bfd *bfd) OVS_REQUIRES(mutex)
>  {
> @@ -1083,6 +1156,28 @@ bfd_diag_str(enum diag diag) {
>      }
>  };
>
> +static const char *bfd_ip_str(ovs_be32 ip) {
> +    static char buf[INET_ADDRSTRLEN];
> +    struct ds ds = DS_EMPTY_INITIALIZER;
> +
> +    ds_put_format(&ds, IP_FMT, IP_ARGS(ip));
> +
> +    ovs_strlcpy(buf, ds_cstr(&ds), sizeof buf);
> +    ds_destroy(&ds);
> +    return buf;
> +}
> +
> +static const char *bfd_ipv6_str(struct in6_addr ipv6) {
> +    static char buf[INET6_ADDRSTRLEN];
> +    struct ds ds = DS_EMPTY_INITIALIZER;
> +
> +    ipv6_format_addr(&ipv6, &ds);
> +
> +    ovs_strlcpy(buf, ds_cstr(&ds), sizeof buf);
> +    ds_destroy(&ds);
> +    return buf;
> +}
> +
>  static void
>  log_msg(enum vlog_level level, const struct msg *p, const char *message,
>          const struct bfd *bfd) OVS_REQUIRES(mutex)
> diff --git a/tests/bfd.at b/tests/bfd.at
> index f5c6409f6..14aac0a19 100644
> --- a/tests/bfd.at
> +++ b/tests/bfd.at
> @@ -1133,3 +1133,33 @@ Datapath actions: 100
>
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> +
> +AT_SETUP([bfd - ipv6])
> +OVS_VSWITCHD_START(
> +  [add-br br1 -- \
> +   set bridge br1 datapath-type=dummy -- \
> +])
> +
> +AT_CHECK([ovs-vsctl add-port br0 p1 -- \
> +   set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p0.sock 
> bfd:enable=true bfd:bfd_src_ipv6=fe80::1 bfd:bfd_dst_ipv6=fe80::2 -- \
> +])
> +
> +AT_CHECK([ovs-vsctl add-port br1 p2 -- \
> +   set interface p2 type=dummy options:stream=unix:$OVS_RUNDIR/p0.sock 
> bfd:enable=true bfd:bfd_src_ipv6=fe80::2 bfd:bfd_dst_ipv6=fe80::1 -- \
> +])
> +
> +ovs-appctl time/stop
> +ovs-appctl time/warp 4100 100
> +
> +# Forwarding should be true
> +BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], 
> [up], [No Diagnostic])
> +BFD_CHECK([p2], [true], [false], [none], [up], [No Diagnostic], [none], 
> [up], [No Diagnostic])
> +
> +# Disable bfd on p2, forwarding on p1 should go to false
> +AT_CHECK([ovs-vsctl set interface p2 bfd:enable=false])
> +
> +ovs-appctl time/warp 5000 100
> +BFD_CHECK([p1], [false], [false], [none], [down], [Control Detection Time 
> Expired], [none], [down], [No Diagnostic])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index cc1dd77ec..e4a8d8d6d 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -3964,6 +3964,16 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 
> type=patch options:peer=p1 \
>            for transmitted BFD packets.  The default is 
> <code>169.254.1.0</code>.
>          </column>
>
> +        <column name="bfd" key="bfd_src_ipv6">
> +          Set to an IPv6 address to set the IP address used as source for
> +          transmitted BFD packets.
> +        </column>
> +
> +        <column name="bfd" key="bfd_dst_ipv6">
> +          Set to an IPv6 address to set the IP address used as destination
> +          for transmitted BFD packets.
> +        </column>
> +
>          <column name="bfd" key="oam">
>            Some tunnel protocols (such as Geneve) include a bit in the header
>            to indicate that the encapsulated packet is an OAM frame. By 
> setting
> --
> 2.25.1
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to