linux/net/openvswitch/dp_notify.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2007-2012 Nicira, Inc.
   4 */
   5
   6#include <linux/netdevice.h>
   7#include <net/genetlink.h>
   8#include <net/netns/generic.h>
   9
  10#include "datapath.h"
  11#include "vport-internal_dev.h"
  12#include "vport-netdev.h"
  13
  14static void dp_detach_port_notify(struct vport *vport)
  15{
  16        struct sk_buff *notify;
  17        struct datapath *dp;
  18
  19        dp = vport->dp;
  20        notify = ovs_vport_cmd_build_info(vport, ovs_dp_get_net(dp),
  21                                          0, 0, OVS_VPORT_CMD_DEL);
  22        ovs_dp_detach_port(vport);
  23        if (IS_ERR(notify)) {
  24                genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0,
  25                             0, PTR_ERR(notify));
  26                return;
  27        }
  28
  29        genlmsg_multicast_netns(&dp_vport_genl_family,
  30                                ovs_dp_get_net(dp), notify, 0,
  31                                0, GFP_KERNEL);
  32}
  33
  34void ovs_dp_notify_wq(struct work_struct *work)
  35{
  36        struct ovs_net *ovs_net = container_of(work, struct ovs_net, dp_notify_work);
  37        struct datapath *dp;
  38
  39        ovs_lock();
  40        list_for_each_entry(dp, &ovs_net->dps, list_node) {
  41                int i;
  42
  43                for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
  44                        struct vport *vport;
  45                        struct hlist_node *n;
  46
  47                        hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) {
  48                                if (vport->ops->type == OVS_VPORT_TYPE_INTERNAL)
  49                                        continue;
  50
  51                                if (!(netif_is_ovs_port(vport->dev)))
  52                                        dp_detach_port_notify(vport);
  53                        }
  54                }
  55        }
  56        ovs_unlock();
  57}
  58
  59static int dp_device_event(struct notifier_block *unused, unsigned long event,
  60                           void *ptr)
  61{
  62        struct ovs_net *ovs_net;
  63        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  64        struct vport *vport = NULL;
  65
  66        if (!ovs_is_internal_dev(dev))
  67                vport = ovs_netdev_get_vport(dev);
  68
  69        if (!vport)
  70                return NOTIFY_DONE;
  71
  72        if (event == NETDEV_UNREGISTER) {
  73                /* upper_dev_unlink and decrement promisc immediately */
  74                ovs_netdev_detach_dev(vport);
  75
  76                /* schedule vport destroy, dev_put and genl notification */
  77                ovs_net = net_generic(dev_net(dev), ovs_net_id);
  78                queue_work(system_wq, &ovs_net->dp_notify_work);
  79        }
  80
  81        return NOTIFY_DONE;
  82}
  83
  84struct notifier_block ovs_dp_device_notifier = {
  85        .notifier_call = dp_device_event
  86};
  87