linux/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Netronome Systems, Inc.
   3 *
   4 * This software is dual licensed under the GNU General License Version 2,
   5 * June 1991 as shown in the file COPYING in the top-level directory of this
   6 * source tree or the BSD 2-Clause License provided below.  You have the
   7 * option to license this software under the complete terms of either license.
   8 *
   9 * The BSD 2-Clause License:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      1. Redistributions of source code must retain the above
  16 *         copyright notice, this list of conditions and the following
  17 *         disclaimer.
  18 *
  19 *      2. Redistributions in binary form must reproduce the above
  20 *         copyright notice, this list of conditions and the following
  21 *         disclaimer in the documentation and/or other materials
  22 *         provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34#include <linux/etherdevice.h>
  35#include <linux/inetdevice.h>
  36#include <net/netevent.h>
  37#include <linux/idr.h>
  38#include <net/dst_metadata.h>
  39#include <net/arp.h>
  40
  41#include "cmsg.h"
  42#include "main.h"
  43#include "../nfp_net_repr.h"
  44#include "../nfp_net.h"
  45
  46#define NFP_FL_MAX_ROUTES               32
  47
  48/**
  49 * struct nfp_tun_active_tuns - periodic message of active tunnels
  50 * @seq:                sequence number of the message
  51 * @count:              number of tunnels report in message
  52 * @flags:              options part of the request
  53 * @tun_info.ipv4:              dest IPv4 address of active route
  54 * @tun_info.egress_port:       port the encapsulated packet egressed
  55 * @tun_info.extra:             reserved for future use
  56 * @tun_info:           tunnels that have sent traffic in reported period
  57 */
  58struct nfp_tun_active_tuns {
  59        __be32 seq;
  60        __be32 count;
  61        __be32 flags;
  62        struct route_ip_info {
  63                __be32 ipv4;
  64                __be32 egress_port;
  65                __be32 extra[2];
  66        } tun_info[];
  67};
  68
  69/**
  70 * struct nfp_tun_neigh - neighbour/route entry on the NFP
  71 * @dst_ipv4:   destination IPv4 address
  72 * @src_ipv4:   source IPv4 address
  73 * @dst_addr:   destination MAC address
  74 * @src_addr:   source MAC address
  75 * @port_id:    NFP port to output packet on - associated with source IPv4
  76 */
  77struct nfp_tun_neigh {
  78        __be32 dst_ipv4;
  79        __be32 src_ipv4;
  80        u8 dst_addr[ETH_ALEN];
  81        u8 src_addr[ETH_ALEN];
  82        __be32 port_id;
  83};
  84
  85/**
  86 * struct nfp_tun_req_route_ipv4 - NFP requests a route/neighbour lookup
  87 * @ingress_port:       ingress port of packet that signalled request
  88 * @ipv4_addr:          destination ipv4 address for route
  89 * @reserved:           reserved for future use
  90 */
  91struct nfp_tun_req_route_ipv4 {
  92        __be32 ingress_port;
  93        __be32 ipv4_addr;
  94        __be32 reserved[2];
  95};
  96
  97/**
  98 * struct nfp_ipv4_route_entry - routes that are offloaded to the NFP
  99 * @ipv4_addr:  destination of route
 100 * @list:       list pointer
 101 */
 102struct nfp_ipv4_route_entry {
 103        __be32 ipv4_addr;
 104        struct list_head list;
 105};
 106
 107#define NFP_FL_IPV4_ADDRS_MAX        32
 108
 109/**
 110 * struct nfp_tun_ipv4_addr - set the IP address list on the NFP
 111 * @count:      number of IPs populated in the array
 112 * @ipv4_addr:  array of IPV4_ADDRS_MAX 32 bit IPv4 addresses
 113 */
 114struct nfp_tun_ipv4_addr {
 115        __be32 count;
 116        __be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
 117};
 118
 119/**
 120 * struct nfp_ipv4_addr_entry - cached IPv4 addresses
 121 * @ipv4_addr:  IP address
 122 * @ref_count:  number of rules currently using this IP
 123 * @list:       list pointer
 124 */
 125struct nfp_ipv4_addr_entry {
 126        __be32 ipv4_addr;
 127        int ref_count;
 128        struct list_head list;
 129};
 130
 131/**
 132 * struct nfp_tun_mac_addr - configure MAC address of tunnel EP on NFP
 133 * @reserved:   reserved for future use
 134 * @count:      number of MAC addresses in the message
 135 * @addresses.index:    index of MAC address in the lookup table
 136 * @addresses.addr:     interface MAC address
 137 * @addresses:  series of MACs to offload
 138 */
 139struct nfp_tun_mac_addr {
 140        __be16 reserved;
 141        __be16 count;
 142        struct index_mac_addr {
 143                __be16 index;
 144                u8 addr[ETH_ALEN];
 145        } addresses[];
 146};
 147
 148/**
 149 * struct nfp_tun_mac_offload_entry - list of MACs to offload
 150 * @index:      index of MAC address for offloading
 151 * @addr:       interface MAC address
 152 * @list:       list pointer
 153 */
 154struct nfp_tun_mac_offload_entry {
 155        __be16 index;
 156        u8 addr[ETH_ALEN];
 157        struct list_head list;
 158};
 159
 160#define NFP_MAX_MAC_INDEX       0xff
 161
 162/**
 163 * struct nfp_tun_mac_non_nfp_idx - converts non NFP netdev ifindex to 8-bit id
 164 * @ifindex:    netdev ifindex of the device
 165 * @index:      index of netdevs mac on NFP
 166 * @list:       list pointer
 167 */
 168struct nfp_tun_mac_non_nfp_idx {
 169        int ifindex;
 170        u8 index;
 171        struct list_head list;
 172};
 173
 174void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
 175{
 176        struct nfp_tun_active_tuns *payload;
 177        struct net_device *netdev;
 178        int count, i, pay_len;
 179        struct neighbour *n;
 180        __be32 ipv4_addr;
 181        u32 port;
 182
 183        payload = nfp_flower_cmsg_get_data(skb);
 184        count = be32_to_cpu(payload->count);
 185        if (count > NFP_FL_MAX_ROUTES) {
 186                nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
 187                return;
 188        }
 189
 190        pay_len = nfp_flower_cmsg_get_data_len(skb);
 191        if (pay_len != sizeof(struct nfp_tun_active_tuns) +
 192            sizeof(struct route_ip_info) * count) {
 193                nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
 194                return;
 195        }
 196
 197        for (i = 0; i < count; i++) {
 198                ipv4_addr = payload->tun_info[i].ipv4;
 199                port = be32_to_cpu(payload->tun_info[i].egress_port);
 200                netdev = nfp_app_repr_get(app, port);
 201                if (!netdev)
 202                        continue;
 203
 204                n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev);
 205                if (!n)
 206                        continue;
 207
 208                /* Update the used timestamp of neighbour */
 209                neigh_event_send(n, NULL);
 210                neigh_release(n);
 211        }
 212}
 213
 214static bool nfp_tun_is_netdev_to_offload(struct net_device *netdev)
 215{
 216        if (!netdev->rtnl_link_ops)
 217                return false;
 218        if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch"))
 219                return true;
 220        if (!strcmp(netdev->rtnl_link_ops->kind, "vxlan"))
 221                return true;
 222
 223        return false;
 224}
 225
 226static int
 227nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
 228                         gfp_t flag)
 229{
 230        struct sk_buff *skb;
 231        unsigned char *msg;
 232
 233        skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
 234        if (!skb)
 235                return -ENOMEM;
 236
 237        msg = nfp_flower_cmsg_get_data(skb);
 238        memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
 239
 240        nfp_ctrl_tx(app->ctrl, skb);
 241        return 0;
 242}
 243
 244static bool nfp_tun_has_route(struct nfp_app *app, __be32 ipv4_addr)
 245{
 246        struct nfp_flower_priv *priv = app->priv;
 247        struct nfp_ipv4_route_entry *entry;
 248        struct list_head *ptr, *storage;
 249
 250        spin_lock_bh(&priv->nfp_neigh_off_lock);
 251        list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
 252                entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
 253                if (entry->ipv4_addr == ipv4_addr) {
 254                        spin_unlock_bh(&priv->nfp_neigh_off_lock);
 255                        return true;
 256                }
 257        }
 258        spin_unlock_bh(&priv->nfp_neigh_off_lock);
 259        return false;
 260}
 261
 262static void nfp_tun_add_route_to_cache(struct nfp_app *app, __be32 ipv4_addr)
 263{
 264        struct nfp_flower_priv *priv = app->priv;
 265        struct nfp_ipv4_route_entry *entry;
 266        struct list_head *ptr, *storage;
 267
 268        spin_lock_bh(&priv->nfp_neigh_off_lock);
 269        list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
 270                entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
 271                if (entry->ipv4_addr == ipv4_addr) {
 272                        spin_unlock_bh(&priv->nfp_neigh_off_lock);
 273                        return;
 274                }
 275        }
 276        entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
 277        if (!entry) {
 278                spin_unlock_bh(&priv->nfp_neigh_off_lock);
 279                nfp_flower_cmsg_warn(app, "Mem error when storing new route.\n");
 280                return;
 281        }
 282
 283        entry->ipv4_addr = ipv4_addr;
 284        list_add_tail(&entry->list, &priv->nfp_neigh_off_list);
 285        spin_unlock_bh(&priv->nfp_neigh_off_lock);
 286}
 287
 288static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr)
 289{
 290        struct nfp_flower_priv *priv = app->priv;
 291        struct nfp_ipv4_route_entry *entry;
 292        struct list_head *ptr, *storage;
 293
 294        spin_lock_bh(&priv->nfp_neigh_off_lock);
 295        list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
 296                entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
 297                if (entry->ipv4_addr == ipv4_addr) {
 298                        list_del(&entry->list);
 299                        kfree(entry);
 300                        break;
 301                }
 302        }
 303        spin_unlock_bh(&priv->nfp_neigh_off_lock);
 304}
 305
 306static void
 307nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
 308                    struct flowi4 *flow, struct neighbour *neigh, gfp_t flag)
 309{
 310        struct nfp_tun_neigh payload;
 311
 312        /* Only offload representor IPv4s for now. */
 313        if (!nfp_netdev_is_nfp_repr(netdev))
 314                return;
 315
 316        memset(&payload, 0, sizeof(struct nfp_tun_neigh));
 317        payload.dst_ipv4 = flow->daddr;
 318
 319        /* If entry has expired send dst IP with all other fields 0. */
 320        if (!(neigh->nud_state & NUD_VALID)) {
 321                nfp_tun_del_route_from_cache(app, payload.dst_ipv4);
 322                /* Trigger ARP to verify invalid neighbour state. */
 323                neigh_event_send(neigh, NULL);
 324                goto send_msg;
 325        }
 326
 327        /* Have a valid neighbour so populate rest of entry. */
 328        payload.src_ipv4 = flow->saddr;
 329        ether_addr_copy(payload.src_addr, netdev->dev_addr);
 330        neigh_ha_snapshot(payload.dst_addr, neigh, netdev);
 331        payload.port_id = cpu_to_be32(nfp_repr_get_port_id(netdev));
 332        /* Add destination of new route to NFP cache. */
 333        nfp_tun_add_route_to_cache(app, payload.dst_ipv4);
 334
 335send_msg:
 336        nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH,
 337                                 sizeof(struct nfp_tun_neigh),
 338                                 (unsigned char *)&payload, flag);
 339}
 340
 341static int
 342nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 343                            void *ptr)
 344{
 345        struct nfp_flower_priv *app_priv;
 346        struct netevent_redirect *redir;
 347        struct flowi4 flow = {};
 348        struct neighbour *n;
 349        struct nfp_app *app;
 350        struct rtable *rt;
 351        int err;
 352
 353        switch (event) {
 354        case NETEVENT_REDIRECT:
 355                redir = (struct netevent_redirect *)ptr;
 356                n = redir->neigh;
 357                break;
 358        case NETEVENT_NEIGH_UPDATE:
 359                n = (struct neighbour *)ptr;
 360                break;
 361        default:
 362                return NOTIFY_DONE;
 363        }
 364
 365        flow.daddr = *(__be32 *)n->primary_key;
 366
 367        /* Only concerned with route changes for representors. */
 368        if (!nfp_netdev_is_nfp_repr(n->dev))
 369                return NOTIFY_DONE;
 370
 371        app_priv = container_of(nb, struct nfp_flower_priv, nfp_tun_neigh_nb);
 372        app = app_priv->app;
 373
 374        /* Only concerned with changes to routes already added to NFP. */
 375        if (!nfp_tun_has_route(app, flow.daddr))
 376                return NOTIFY_DONE;
 377
 378#if IS_ENABLED(CONFIG_INET)
 379        /* Do a route lookup to populate flow data. */
 380        rt = ip_route_output_key(dev_net(n->dev), &flow);
 381        err = PTR_ERR_OR_ZERO(rt);
 382        if (err)
 383                return NOTIFY_DONE;
 384#else
 385        return NOTIFY_DONE;
 386#endif
 387
 388        flow.flowi4_proto = IPPROTO_UDP;
 389        nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_ATOMIC);
 390
 391        return NOTIFY_OK;
 392}
 393
 394void nfp_tunnel_request_route(struct nfp_app *app, struct sk_buff *skb)
 395{
 396        struct nfp_tun_req_route_ipv4 *payload;
 397        struct net_device *netdev;
 398        struct flowi4 flow = {};
 399        struct neighbour *n;
 400        struct rtable *rt;
 401        int err;
 402
 403        payload = nfp_flower_cmsg_get_data(skb);
 404
 405        netdev = nfp_app_repr_get(app, be32_to_cpu(payload->ingress_port));
 406        if (!netdev)
 407                goto route_fail_warning;
 408
 409        flow.daddr = payload->ipv4_addr;
 410        flow.flowi4_proto = IPPROTO_UDP;
 411
 412#if IS_ENABLED(CONFIG_INET)
 413        /* Do a route lookup on same namespace as ingress port. */
 414        rt = ip_route_output_key(dev_net(netdev), &flow);
 415        err = PTR_ERR_OR_ZERO(rt);
 416        if (err)
 417                goto route_fail_warning;
 418#else
 419        goto route_fail_warning;
 420#endif
 421
 422        /* Get the neighbour entry for the lookup */
 423        n = dst_neigh_lookup(&rt->dst, &flow.daddr);
 424        ip_rt_put(rt);
 425        if (!n)
 426                goto route_fail_warning;
 427        nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_KERNEL);
 428        neigh_release(n);
 429        return;
 430
 431route_fail_warning:
 432        nfp_flower_cmsg_warn(app, "Requested route not found.\n");
 433}
 434
 435static void nfp_tun_write_ipv4_list(struct nfp_app *app)
 436{
 437        struct nfp_flower_priv *priv = app->priv;
 438        struct nfp_ipv4_addr_entry *entry;
 439        struct nfp_tun_ipv4_addr payload;
 440        struct list_head *ptr, *storage;
 441        int count;
 442
 443        memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
 444        mutex_lock(&priv->nfp_ipv4_off_lock);
 445        count = 0;
 446        list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
 447                if (count >= NFP_FL_IPV4_ADDRS_MAX) {
 448                        mutex_unlock(&priv->nfp_ipv4_off_lock);
 449                        nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
 450                        return;
 451                }
 452                entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 453                payload.ipv4_addr[count++] = entry->ipv4_addr;
 454        }
 455        payload.count = cpu_to_be32(count);
 456        mutex_unlock(&priv->nfp_ipv4_off_lock);
 457
 458        nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS,
 459                                 sizeof(struct nfp_tun_ipv4_addr),
 460                                 &payload, GFP_KERNEL);
 461}
 462
 463void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
 464{
 465        struct nfp_flower_priv *priv = app->priv;
 466        struct nfp_ipv4_addr_entry *entry;
 467        struct list_head *ptr, *storage;
 468
 469        mutex_lock(&priv->nfp_ipv4_off_lock);
 470        list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
 471                entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 472                if (entry->ipv4_addr == ipv4) {
 473                        entry->ref_count++;
 474                        mutex_unlock(&priv->nfp_ipv4_off_lock);
 475                        return;
 476                }
 477        }
 478
 479        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 480        if (!entry) {
 481                mutex_unlock(&priv->nfp_ipv4_off_lock);
 482                nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
 483                return;
 484        }
 485        entry->ipv4_addr = ipv4;
 486        entry->ref_count = 1;
 487        list_add_tail(&entry->list, &priv->nfp_ipv4_off_list);
 488        mutex_unlock(&priv->nfp_ipv4_off_lock);
 489
 490        nfp_tun_write_ipv4_list(app);
 491}
 492
 493void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4)
 494{
 495        struct nfp_flower_priv *priv = app->priv;
 496        struct nfp_ipv4_addr_entry *entry;
 497        struct list_head *ptr, *storage;
 498
 499        mutex_lock(&priv->nfp_ipv4_off_lock);
 500        list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
 501                entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 502                if (entry->ipv4_addr == ipv4) {
 503                        entry->ref_count--;
 504                        if (!entry->ref_count) {
 505                                list_del(&entry->list);
 506                                kfree(entry);
 507                        }
 508                        break;
 509                }
 510        }
 511        mutex_unlock(&priv->nfp_ipv4_off_lock);
 512
 513        nfp_tun_write_ipv4_list(app);
 514}
 515
 516void nfp_tunnel_write_macs(struct nfp_app *app)
 517{
 518        struct nfp_flower_priv *priv = app->priv;
 519        struct nfp_tun_mac_offload_entry *entry;
 520        struct nfp_tun_mac_addr *payload;
 521        struct list_head *ptr, *storage;
 522        int mac_count, err, pay_size;
 523
 524        mutex_lock(&priv->nfp_mac_off_lock);
 525        if (!priv->nfp_mac_off_count) {
 526                mutex_unlock(&priv->nfp_mac_off_lock);
 527                return;
 528        }
 529
 530        pay_size = sizeof(struct nfp_tun_mac_addr) +
 531                   sizeof(struct index_mac_addr) * priv->nfp_mac_off_count;
 532
 533        payload = kzalloc(pay_size, GFP_KERNEL);
 534        if (!payload) {
 535                mutex_unlock(&priv->nfp_mac_off_lock);
 536                return;
 537        }
 538
 539        payload->count = cpu_to_be16(priv->nfp_mac_off_count);
 540
 541        mac_count = 0;
 542        list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
 543                entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
 544                                   list);
 545                payload->addresses[mac_count].index = entry->index;
 546                ether_addr_copy(payload->addresses[mac_count].addr,
 547                                entry->addr);
 548                mac_count++;
 549        }
 550
 551        err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC,
 552                                       pay_size, payload, GFP_KERNEL);
 553
 554        kfree(payload);
 555
 556        if (err) {
 557                mutex_unlock(&priv->nfp_mac_off_lock);
 558                /* Write failed so retain list for future retry. */
 559                return;
 560        }
 561
 562        /* If list was successfully offloaded, flush it. */
 563        list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
 564                entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
 565                                   list);
 566                list_del(&entry->list);
 567                kfree(entry);
 568        }
 569
 570        priv->nfp_mac_off_count = 0;
 571        mutex_unlock(&priv->nfp_mac_off_lock);
 572}
 573
 574static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex)
 575{
 576        struct nfp_flower_priv *priv = app->priv;
 577        struct nfp_tun_mac_non_nfp_idx *entry;
 578        struct list_head *ptr, *storage;
 579        int idx;
 580
 581        mutex_lock(&priv->nfp_mac_index_lock);
 582        list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
 583                entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list);
 584                if (entry->ifindex == ifindex) {
 585                        idx = entry->index;
 586                        mutex_unlock(&priv->nfp_mac_index_lock);
 587                        return idx;
 588                }
 589        }
 590
 591        idx = ida_simple_get(&priv->nfp_mac_off_ids, 0,
 592                             NFP_MAX_MAC_INDEX, GFP_KERNEL);
 593        if (idx < 0) {
 594                mutex_unlock(&priv->nfp_mac_index_lock);
 595                return idx;
 596        }
 597
 598        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 599        if (!entry) {
 600                mutex_unlock(&priv->nfp_mac_index_lock);
 601                return -ENOMEM;
 602        }
 603        entry->ifindex = ifindex;
 604        entry->index = idx;
 605        list_add_tail(&entry->list, &priv->nfp_mac_index_list);
 606        mutex_unlock(&priv->nfp_mac_index_lock);
 607
 608        return idx;
 609}
 610
 611static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex)
 612{
 613        struct nfp_flower_priv *priv = app->priv;
 614        struct nfp_tun_mac_non_nfp_idx *entry;
 615        struct list_head *ptr, *storage;
 616
 617        mutex_lock(&priv->nfp_mac_index_lock);
 618        list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
 619                entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list);
 620                if (entry->ifindex == ifindex) {
 621                        ida_simple_remove(&priv->nfp_mac_off_ids,
 622                                          entry->index);
 623                        list_del(&entry->list);
 624                        kfree(entry);
 625                        break;
 626                }
 627        }
 628        mutex_unlock(&priv->nfp_mac_index_lock);
 629}
 630
 631static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev,
 632                                            struct nfp_app *app)
 633{
 634        struct nfp_flower_priv *priv = app->priv;
 635        struct nfp_tun_mac_offload_entry *entry;
 636        u16 nfp_mac_idx;
 637        int port = 0;
 638
 639        /* Check if MAC should be offloaded. */
 640        if (!is_valid_ether_addr(netdev->dev_addr))
 641                return;
 642
 643        if (nfp_netdev_is_nfp_repr(netdev))
 644                port = nfp_repr_get_port_id(netdev);
 645        else if (!nfp_tun_is_netdev_to_offload(netdev))
 646                return;
 647
 648        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 649        if (!entry) {
 650                nfp_flower_cmsg_warn(app, "Mem fail when offloading MAC.\n");
 651                return;
 652        }
 653
 654        if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
 655            NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) {
 656                nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
 657        } else if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
 658                   NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT) {
 659                port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port);
 660                nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT;
 661        } else {
 662                /* Must assign our own unique 8-bit index. */
 663                int idx = nfp_tun_get_mac_idx(app, netdev->ifindex);
 664
 665                if (idx < 0) {
 666                        nfp_flower_cmsg_warn(app, "Can't assign non-repr MAC index.\n");
 667                        kfree(entry);
 668                        return;
 669                }
 670                nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
 671        }
 672
 673        entry->index = cpu_to_be16(nfp_mac_idx);
 674        ether_addr_copy(entry->addr, netdev->dev_addr);
 675
 676        mutex_lock(&priv->nfp_mac_off_lock);
 677        priv->nfp_mac_off_count++;
 678        list_add_tail(&entry->list, &priv->nfp_mac_off_list);
 679        mutex_unlock(&priv->nfp_mac_off_lock);
 680}
 681
 682static int nfp_tun_mac_event_handler(struct notifier_block *nb,
 683                                     unsigned long event, void *ptr)
 684{
 685        struct nfp_flower_priv *app_priv;
 686        struct net_device *netdev;
 687        struct nfp_app *app;
 688
 689        if (event == NETDEV_DOWN || event == NETDEV_UNREGISTER) {
 690                app_priv = container_of(nb, struct nfp_flower_priv,
 691                                        nfp_tun_mac_nb);
 692                app = app_priv->app;
 693                netdev = netdev_notifier_info_to_dev(ptr);
 694
 695                /* If non-nfp netdev then free its offload index. */
 696                if (nfp_tun_is_netdev_to_offload(netdev))
 697                        nfp_tun_del_mac_idx(app, netdev->ifindex);
 698        } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR ||
 699                   event == NETDEV_REGISTER) {
 700                app_priv = container_of(nb, struct nfp_flower_priv,
 701                                        nfp_tun_mac_nb);
 702                app = app_priv->app;
 703                netdev = netdev_notifier_info_to_dev(ptr);
 704
 705                nfp_tun_add_to_mac_offload_list(netdev, app);
 706
 707                /* Force a list write to keep NFP up to date. */
 708                nfp_tunnel_write_macs(app);
 709        }
 710        return NOTIFY_OK;
 711}
 712
 713int nfp_tunnel_config_start(struct nfp_app *app)
 714{
 715        struct nfp_flower_priv *priv = app->priv;
 716        struct net_device *netdev;
 717        int err;
 718
 719        /* Initialise priv data for MAC offloading. */
 720        priv->nfp_mac_off_count = 0;
 721        mutex_init(&priv->nfp_mac_off_lock);
 722        INIT_LIST_HEAD(&priv->nfp_mac_off_list);
 723        priv->nfp_tun_mac_nb.notifier_call = nfp_tun_mac_event_handler;
 724        mutex_init(&priv->nfp_mac_index_lock);
 725        INIT_LIST_HEAD(&priv->nfp_mac_index_list);
 726        ida_init(&priv->nfp_mac_off_ids);
 727
 728        /* Initialise priv data for IPv4 offloading. */
 729        mutex_init(&priv->nfp_ipv4_off_lock);
 730        INIT_LIST_HEAD(&priv->nfp_ipv4_off_list);
 731
 732        /* Initialise priv data for neighbour offloading. */
 733        spin_lock_init(&priv->nfp_neigh_off_lock);
 734        INIT_LIST_HEAD(&priv->nfp_neigh_off_list);
 735        priv->nfp_tun_neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
 736
 737        err = register_netdevice_notifier(&priv->nfp_tun_mac_nb);
 738        if (err)
 739                goto err_free_mac_ida;
 740
 741        err = register_netevent_notifier(&priv->nfp_tun_neigh_nb);
 742        if (err)
 743                goto err_unreg_mac_nb;
 744
 745        /* Parse netdevs already registered for MACs that need offloaded. */
 746        rtnl_lock();
 747        for_each_netdev(&init_net, netdev)
 748                nfp_tun_add_to_mac_offload_list(netdev, app);
 749        rtnl_unlock();
 750
 751        return 0;
 752
 753err_unreg_mac_nb:
 754        unregister_netdevice_notifier(&priv->nfp_tun_mac_nb);
 755err_free_mac_ida:
 756        ida_destroy(&priv->nfp_mac_off_ids);
 757        return err;
 758}
 759
 760void nfp_tunnel_config_stop(struct nfp_app *app)
 761{
 762        struct nfp_tun_mac_offload_entry *mac_entry;
 763        struct nfp_flower_priv *priv = app->priv;
 764        struct nfp_ipv4_route_entry *route_entry;
 765        struct nfp_tun_mac_non_nfp_idx *mac_idx;
 766        struct nfp_ipv4_addr_entry *ip_entry;
 767        struct list_head *ptr, *storage;
 768
 769        unregister_netdevice_notifier(&priv->nfp_tun_mac_nb);
 770        unregister_netevent_notifier(&priv->nfp_tun_neigh_nb);
 771
 772        /* Free any memory that may be occupied by MAC list. */
 773        list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
 774                mac_entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
 775                                       list);
 776                list_del(&mac_entry->list);
 777                kfree(mac_entry);
 778        }
 779
 780        /* Free any memory that may be occupied by MAC index list. */
 781        list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
 782                mac_idx = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx,
 783                                     list);
 784                list_del(&mac_idx->list);
 785                kfree(mac_idx);
 786        }
 787
 788        ida_destroy(&priv->nfp_mac_off_ids);
 789
 790        /* Free any memory that may be occupied by ipv4 list. */
 791        list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
 792                ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 793                list_del(&ip_entry->list);
 794                kfree(ip_entry);
 795        }
 796
 797        /* Free any memory that may be occupied by the route list. */
 798        list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
 799                route_entry = list_entry(ptr, struct nfp_ipv4_route_entry,
 800                                         list);
 801                list_del(&route_entry->list);
 802                kfree(route_entry);
 803        }
 804}
 805