All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit b7320746 authored by Alex Wang's avatar Alex Wang

rtnetlink: Extend rtnetlink to support RTNLGRP_IPV4_IFADDR and

RTNLGRP_IPV6_IFADDR.

This commit renames the rtnetlink-link.{c,h} to rtnetlink.{c,h}
and extends the module to support RTNLGRP_IPV4_IFADDR and
RTNLGRP_IPV4_IFADDR multicast groups.  A later patch will start
using this module to react to interface address changes.
Signed-off-by: default avatarAlex Wang <alexw@nicira.com>
Acked-by: default avatarBen Pfaff <blp@nicira.com>
parent 6dba08e3
......@@ -343,8 +343,8 @@ lib_libopenvswitch_la_SOURCES += \
lib/netlink-socket.h \
lib/ovs-numa.c \
lib/ovs-numa.h \
lib/rtnetlink-link.c \
lib/rtnetlink-link.h \
lib/rtnetlink.c \
lib/rtnetlink.h \
lib/route-table.c \
lib/route-table.h
endif
......
......@@ -66,7 +66,7 @@
#include "ovs-atomic.h"
#include "packets.h"
#include "poll-loop.h"
#include "rtnetlink-link.h"
#include "rtnetlink.h"
#include "shash.h"
#include "socket-util.h"
#include "sset.h"
......@@ -541,7 +541,7 @@ netdev_rxq_linux_cast(const struct netdev_rxq *rx)
}
static void netdev_linux_update(struct netdev_linux *netdev,
const struct rtnetlink_link_change *)
const struct rtnetlink_change *)
OVS_REQUIRES(netdev->mutex);
static void netdev_linux_changed(struct netdev_linux *netdev,
unsigned int ifi_flags, unsigned int mask)
......@@ -601,9 +601,9 @@ netdev_linux_run(void)
ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
error = nl_sock_recv(sock, &buf, false);
if (!error) {
struct rtnetlink_link_change change;
struct rtnetlink_change change;
if (rtnetlink_link_parse(&buf, &change)) {
if (rtnetlink_parse(&buf, &change)) {
struct netdev *netdev_ = netdev_from_name(change.ifname);
if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
......@@ -674,7 +674,7 @@ netdev_linux_changed(struct netdev_linux *dev,
static void
netdev_linux_update(struct netdev_linux *dev,
const struct rtnetlink_link_change *change)
const struct rtnetlink_change *change)
OVS_REQUIRES(dev->mutex)
{
if (change->nlmsg_type == RTM_NEWLINK) {
......@@ -694,10 +694,9 @@ netdev_linux_update(struct netdev_linux *dev,
dev->ether_addr_error = 0;
}
dev->ifindex = change->ifi_index;
dev->ifindex = change->if_index;
dev->cache_valid |= VALID_IFINDEX;
dev->get_ifindex_error = 0;
} else {
netdev_linux_changed(dev, change->ifi_flags, 0);
}
......
......@@ -30,7 +30,7 @@
#include "netlink-socket.h"
#include "ofpbuf.h"
#include "ovs-router.h"
#include "rtnetlink-link.h"
#include "rtnetlink.h"
#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(route_table);
......@@ -74,7 +74,7 @@ static void route_table_change(const struct route_table_msg *, void *);
static void route_map_clear(void);
static void name_table_init(void);
static void name_table_change(const struct rtnetlink_link_change *, void *);
static void name_table_change(const struct rtnetlink_change *, void *);
uint64_t
route_table_get_change_seq(void)
......@@ -113,7 +113,7 @@ route_table_run(void)
{
ovs_mutex_lock(&route_table_mutex);
if (nln) {
rtnetlink_link_run();
rtnetlink_run();
nln_run(nln);
if (!route_table_valid) {
......@@ -130,7 +130,7 @@ route_table_wait(void)
{
ovs_mutex_lock(&route_table_mutex);
if (nln) {
rtnetlink_link_wait();
rtnetlink_wait();
nln_wait(nln);
}
ovs_mutex_unlock(&route_table_mutex);
......@@ -278,12 +278,12 @@ route_table_fallback_lookup(ovs_be32 ip_dst OVS_UNUSED,
static void
name_table_init(void)
{
name_notifier = rtnetlink_link_notifier_create(name_table_change, NULL);
name_notifier = rtnetlink_notifier_create(name_table_change, NULL);
}
static void
name_table_change(const struct rtnetlink_link_change *change OVS_UNUSED,
name_table_change(const struct rtnetlink_change *change OVS_UNUSED,
void *aux OVS_UNUSED)
{
/* Changes to interface status can cause routing table changes that some
......
/*
* Copyright (c) 2009, 2010, 2013 Nicira, Inc.
* Copyright (c) 2009, 2010, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,7 +16,7 @@
#include <config.h>
#include "rtnetlink-link.h"
#include "rtnetlink.h"
#include <sys/socket.h>
#include <linux/rtnetlink.h>
......@@ -27,56 +27,95 @@
#include "ofpbuf.h"
static struct nln *nln = NULL;
static struct rtnetlink_link_change rtn_change;
static struct rtnetlink_change rtn_change;
/* Returns true if the given netlink msg type corresponds to RTNLGRP_LINK. */
bool
rtnetlink_type_is_rtnlgrp_link(uint16_t type)
{
return type == RTM_NEWLINK || type == RTM_DELLINK;
}
/* Returns true if the given netlink msg type corresponds to
* RTNLGRP_IPV4_IFADDR or RTNLGRP_IPV6_IFADDR. */
bool
rtnetlink_type_is_rtnlgrp_addr(uint16_t type)
{
return type == RTM_NEWADDR || type == RTM_DELADDR;
}
/* Parses a rtnetlink message 'buf' into 'change'. If 'buf' is unparseable,
* leaves 'change' untouched and returns false. Otherwise, populates 'change'
* and returns true. */
bool
rtnetlink_link_parse(struct ofpbuf *buf,
struct rtnetlink_link_change *change)
rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change)
{
bool parsed;
/* Policy for RTNLGRP_LINK messages.
*
* There are *many* more fields in these messages, but currently we
* only care about these fields. */
static const struct nl_policy policy[] = {
[IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
[IFLA_MASTER] = { .type = NL_A_U32, .optional = true },
[IFLA_MTU] = { .type = NL_A_U32, .optional = true },
[IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true },
};
struct nlattr *attrs[ARRAY_SIZE(policy)];
parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
policy, attrs, ARRAY_SIZE(policy));
if (parsed) {
const struct nlmsghdr *nlmsg;
const struct ifinfomsg *ifinfo;
nlmsg = buf->data;
ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
change->nlmsg_type = nlmsg->nlmsg_type;
change->ifi_index = ifinfo->ifi_index;
change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]);
change->ifi_flags = ifinfo->ifi_flags;
change->master_ifindex = (attrs[IFLA_MASTER]
? nl_attr_get_u32(attrs[IFLA_MASTER])
: 0);
change->mtu = (attrs[IFLA_MTU]
? nl_attr_get_u32(attrs[IFLA_MTU])
: 0);
if (attrs[IFLA_ADDRESS] &&
nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) {
memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]), ETH_ALEN);
} else {
memset(change->addr, 0, ETH_ALEN);
const struct nlmsghdr *nlmsg = buf->data;
bool parsed = false;
if (rtnetlink_type_is_rtnlgrp_link(nlmsg->nlmsg_type)) {
/* Policy for RTNLGRP_LINK messages.
*
* There are *many* more fields in these messages, but currently we
* only care about these fields. */
static const struct nl_policy policy[] = {
[IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
[IFLA_MASTER] = { .type = NL_A_U32, .optional = true },
[IFLA_MTU] = { .type = NL_A_U32, .optional = true },
[IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true },
};
struct nlattr *attrs[ARRAY_SIZE(policy)];
parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
policy, attrs, ARRAY_SIZE(policy));
if (parsed) {
const struct ifinfomsg *ifinfo;
ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
change->nlmsg_type = nlmsg->nlmsg_type;
change->if_index = ifinfo->ifi_index;
change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]);
change->ifi_flags = ifinfo->ifi_flags;
change->master_ifindex = (attrs[IFLA_MASTER]
? nl_attr_get_u32(attrs[IFLA_MASTER])
: 0);
change->mtu = (attrs[IFLA_MTU]
? nl_attr_get_u32(attrs[IFLA_MTU])
: 0);
if (attrs[IFLA_ADDRESS] &&
nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) {
memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]),
ETH_ALEN);
} else {
memset(change->addr, 0, ETH_ALEN);
}
}
} else if (rtnetlink_type_is_rtnlgrp_addr(nlmsg->nlmsg_type)) {
/* Policy for RTNLGRP_IPV4_IFADDR/RTNLGRP_IPV6_IFADDR messages.
*
* There are *many* more fields in these messages, but currently we
* only care about these fields. */
static const struct nl_policy policy[] = {
[IFA_LABEL] = { .type = NL_A_STRING, .optional = false },
};
struct nlattr *attrs[ARRAY_SIZE(policy)];
parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifaddrmsg),
policy, attrs, ARRAY_SIZE(policy));
if (parsed) {
const struct ifaddrmsg *ifaddr;
ifaddr = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifaddr);
change->nlmsg_type = nlmsg->nlmsg_type;
change->if_index = ifaddr->ifa_index;
change->ifname = nl_attr_get_string(attrs[IFA_LABEL]);
}
}
......@@ -84,9 +123,9 @@ rtnetlink_link_parse(struct ofpbuf *buf,
}
static bool
rtnetlink_link_parse_cb(struct ofpbuf *buf, void *change)
rtnetlink_parse_cb(struct ofpbuf *buf, void *change)
{
return rtnetlink_link_parse(buf, change);
return rtnetlink_parse(buf, change);
}
/* Registers 'cb' to be called with auxiliary data 'aux' with network device
......@@ -97,12 +136,14 @@ rtnetlink_link_parse_cb(struct ofpbuf *buf, void *change)
* using dpif_port_poll() or netdev_change_seq(), which unlike this function
* are not Linux-specific.
*
* xxx Joins more multicast groups when needed.
*
* Returns an initialized nln_notifier if successful, NULL otherwise. */
struct nln_notifier *
rtnetlink_link_notifier_create(rtnetlink_link_notify_func *cb, void *aux)
rtnetlink_notifier_create(rtnetlink_notify_func *cb, void *aux)
{
if (!nln) {
nln = nln_create(NETLINK_ROUTE, RTNLGRP_LINK, rtnetlink_link_parse_cb,
nln = nln_create(NETLINK_ROUTE, RTNLGRP_LINK, rtnetlink_parse_cb,
&rtn_change);
}
......@@ -110,9 +151,9 @@ rtnetlink_link_notifier_create(rtnetlink_link_notify_func *cb, void *aux)
}
/* Destroys 'notifier', which must have previously been created with
* rtnetlink_link_notifier_register(). */
* rtnetlink_notifier_register(). */
void
rtnetlink_link_notifier_destroy(struct nln_notifier *notifier)
rtnetlink_notifier_destroy(struct nln_notifier *notifier)
{
nln_notifier_destroy(notifier);
}
......@@ -120,7 +161,7 @@ rtnetlink_link_notifier_destroy(struct nln_notifier *notifier)
/* Calls all of the registered notifiers, passing along any as-yet-unreported
* netdev change events. */
void
rtnetlink_link_run(void)
rtnetlink_run(void)
{
if (nln) {
nln_run(nln);
......@@ -130,7 +171,7 @@ rtnetlink_link_run(void)
/* Causes poll_block() to wake up when network device change notifications are
* ready. */
void
rtnetlink_link_wait(void)
rtnetlink_wait(void)
{
if (nln) {
nln_wait(nln);
......
/*
* Copyright (c) 2009 Nicira, Inc.
* Copyright (c) 2009, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -28,36 +28,41 @@ struct nln_notifier;
* Linux-specific code. */
/* A digested version of an rtnetlink_link message sent down by the kernel to
* indicate that a network device has been created, destroyed or changed. */
struct rtnetlink_link_change {
* indicate that a network device's status (link or address) has been changed.
*/
struct rtnetlink_change {
/* Copied from struct nlmsghdr. */
int nlmsg_type; /* e.g. RTM_NEWLINK, RTM_DELLINK. */
/* Copied from struct ifinfomsg. */
int ifi_index; /* Index of network device. */
/* Extracted from Netlink attributes. */
/* Common attributes. */
int if_index; /* Index of network device. */
const char *ifname; /* Name of network device. */
/* Network device link status. */
int master_ifindex; /* Ifindex of datapath master (0 if none). */
int mtu; /* Current MTU. */
uint8_t addr[ETH_ALEN];
unsigned int ifi_flags; /* Flags of network device. */
/* Network device address status. */
/* xxx To be added when needed. */
};
/* Function called to report that a netdev has changed. 'change' describes the
* specific change. It may be null if the buffer of change information
* overflowed, in which case the function must assume that every device may
* have changed. 'aux' is as specified in the call to
* rtnetlink_link_notifier_register(). */
* rtnetlink_notifier_register(). */
typedef
void rtnetlink_link_notify_func(const struct rtnetlink_link_change *change,
void *aux);
void rtnetlink_notify_func(const struct rtnetlink_change *change,
void *aux);
bool rtnetlink_link_parse(struct ofpbuf *buf,
struct rtnetlink_link_change *change);
bool rtnetlink_type_is_rtnlgrp_link(uint16_t type);
bool rtnetlink_type_is_rtnlgrp_addr(uint16_t type);
bool rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change);
struct nln_notifier *
rtnetlink_link_notifier_create(rtnetlink_link_notify_func *, void *aux);
void rtnetlink_link_notifier_destroy(struct nln_notifier *);
void rtnetlink_link_run(void);
void rtnetlink_link_wait(void);
#endif /* rtnetlink-link.h */
rtnetlink_notifier_create(rtnetlink_notify_func *, void *aux);
void rtnetlink_notifier_destroy(struct nln_notifier *);
void rtnetlink_run(void);
void rtnetlink_wait(void);
#endif /* rtnetlink.h */
......@@ -162,7 +162,7 @@ vlandev_get_name(const char *real_dev_name, int vid)
/* The Linux vlandev implementation. */
#ifdef __linux__
#include "rtnetlink-link.h"
#include "rtnetlink.h"
#include <linux/if_vlan.h>
#include <linux/sockios.h>
#include "netdev-linux.h"
......@@ -171,7 +171,7 @@ static struct nln_notifier *vlan_cache_notifier;
static bool cache_valid;
static void
vlan_cache_cb(const struct rtnetlink_link_change *change OVS_UNUSED,
vlan_cache_cb(const struct rtnetlink_change *change OVS_UNUSED,
void *aux OVS_UNUSED)
{
cache_valid = false;
......@@ -185,8 +185,8 @@ vlandev_linux_refresh(void)
FILE *stream;
if (!vlan_cache_notifier) {
vlan_cache_notifier = rtnetlink_link_notifier_create(vlan_cache_cb,
NULL);
vlan_cache_notifier = rtnetlink_notifier_create(vlan_cache_cb,
NULL);
if (!vlan_cache_notifier) {
return EINVAL;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment