Blame fipvlan.c

Packit Service bca4e3
/*
Packit Service bca4e3
 * Copyright(c) 2010 Intel Corporation. All rights reserved.
Packit Service bca4e3
 *
Packit Service bca4e3
 * This program is free software; you can redistribute it and/or modify it
Packit Service bca4e3
 * under the terms and conditions of the GNU General Public License,
Packit Service bca4e3
 * version 2, as published by the Free Software Foundation.
Packit Service bca4e3
 *
Packit Service bca4e3
 * This program is distributed in the hope it will be useful, but WITHOUT
Packit Service bca4e3
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit Service bca4e3
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit Service bca4e3
 * more details.
Packit Service bca4e3
 *
Packit Service bca4e3
 * You should have received a copy of the GNU General Public License along with
Packit Service bca4e3
 * this program; if not, write to the Free Software Foundation, Inc.,
Packit Service bca4e3
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service bca4e3
 *
Packit Service bca4e3
 * Maintained at www.Open-FCoE.org
Packit Service bca4e3
 */
Packit Service bca4e3
Packit Service bca4e3
#include <string.h>
Packit Service bca4e3
#include <stdlib.h>
Packit Service bca4e3
#include <stdio.h>
Packit Service bca4e3
#include <stdarg.h>
Packit Service bca4e3
#include <stdint.h>
Packit Service bca4e3
#include <stdbool.h>
Packit Service bca4e3
#include <unistd.h>
Packit Service bca4e3
#include <errno.h>
Packit Service bca4e3
#include <getopt.h>
Packit Service bca4e3
#include <poll.h>
Packit Service bca4e3
#include <signal.h>
Packit Service bca4e3
#include <sys/ioctl.h>
Packit Service bca4e3
#include <sys/socket.h>
Packit Service bca4e3
#include <sys/queue.h>
Packit Service bca4e3
#include <net/if.h>
Packit Service bca4e3
#include <net/if_arp.h>
Packit Service bca4e3
#include <net/ethernet.h>
Packit Service bca4e3
#include <arpa/inet.h>
Packit Service bca4e3
#include <linux/netlink.h>
Packit Service bca4e3
#include <linux/rtnetlink.h>
Packit Service bca4e3
#include <linux/if_packet.h>
Packit Service bca4e3
#include <linux/capability.h>
Packit Service bca4e3
#include <sys/syscall.h>
Packit Service bca4e3
Packit Service bca4e3
#include <sys/stat.h>
Packit Service bca4e3
#include <fcntl.h>
Packit Service bca4e3
Packit Service bca4e3
#include "fcoe_utils_version.h"
Packit Service bca4e3
#include "fip.h"
Packit Service bca4e3
#include "fcoemon_utils.h"
Packit Service bca4e3
#include "fcoe_utils.h"
Packit Service bca4e3
#include "rtnetlink.h"
Packit Service bca4e3
Packit Service bca4e3
#define FIP_LOG(...)		sa_log(__VA_ARGS__)
Packit Service bca4e3
#define FIP_LOG_ERR(error, ...)	sa_log_err(error, __func__, __VA_ARGS__)
Packit Service bca4e3
#define FIP_LOG_ERRNO(...)	sa_log_err(errno, __func__, __VA_ARGS__)
Packit Service bca4e3
#define FIP_LOG_DBG(...)	sa_log_debug(__VA_ARGS__)
Packit Service bca4e3
Packit Service bca4e3
#define MAX_VLAN_RETRIES	50
Packit Service bca4e3
Packit Service bca4e3
/* global configuration */
Packit Service bca4e3
Packit Service bca4e3
struct {
Packit Service bca4e3
	char **namev;
Packit Service bca4e3
	int namec;
Packit Service bca4e3
	bool automode;
Packit Service bca4e3
	bool create;
Packit Service bca4e3
	bool start;
Packit Service bca4e3
	bool vn2vn;
Packit Service bca4e3
	bool debug;
Packit Service bca4e3
	bool link_up;
Packit Service bca4e3
	int link_retry;
Packit Service bca4e3
	char suffix[256];
Packit Service bca4e3
} config = {
Packit Service bca4e3
	.namev = NULL,
Packit Service bca4e3
	.namec = 0,
Packit Service bca4e3
	.automode = false,
Packit Service bca4e3
	.create = false,
Packit Service bca4e3
	.vn2vn = false,
Packit Service bca4e3
	.debug = false,
Packit Service bca4e3
	.link_up = false,
Packit Service bca4e3
	.link_retry = 20,
Packit Service bca4e3
	.suffix = "",
Packit Service bca4e3
};
Packit Service bca4e3
Packit Service bca4e3
int (*fcoe_instance_start)(const char *ifname);
Packit Service bca4e3
Packit Service bca4e3
char *exe;
Packit Service bca4e3
Packit Service bca4e3
static struct pollfd *pfd = NULL;
Packit Service bca4e3
static int pfd_len = 0;
Packit Service bca4e3
Packit Service bca4e3
static void pfd_add(int fd)
Packit Service bca4e3
{
Packit Service bca4e3
	struct pollfd *npfd;
Packit Service bca4e3
	int i;
Packit Service bca4e3
Packit Service bca4e3
	for (i = 0; i < pfd_len; i++)
Packit Service bca4e3
		if (pfd[i].fd == fd)
Packit Service bca4e3
			return;
Packit Service bca4e3
Packit Service bca4e3
	npfd = realloc(pfd, (pfd_len + 1) * sizeof(struct pollfd));
Packit Service bca4e3
	if (!npfd) {
Packit Service bca4e3
		perror("realloc fail");
Packit Service bca4e3
		return;
Packit Service bca4e3
	}
Packit Service bca4e3
	pfd = npfd;
Packit Service bca4e3
	pfd[pfd_len].fd = fd;
Packit Service bca4e3
	pfd[pfd_len].events = POLLIN;
Packit Service bca4e3
	pfd_len++;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void pfd_remove(int fd)
Packit Service bca4e3
{
Packit Service bca4e3
	struct pollfd *npfd;
Packit Service bca4e3
	int i;
Packit Service bca4e3
Packit Service bca4e3
	for (i = 0; i < pfd_len; i++) {
Packit Service bca4e3
		if (pfd[i].fd == fd)
Packit Service bca4e3
			break;
Packit Service bca4e3
	}
Packit Service bca4e3
	if (i == pfd_len)
Packit Service bca4e3
		return;
Packit Service bca4e3
	memmove(&pfd[i], &pfd[i+1], (--pfd_len - i) * sizeof(struct pollfd));
Packit Service bca4e3
	npfd = realloc(pfd, pfd_len * sizeof(struct pollfd));
Packit Service bca4e3
	if (npfd)
Packit Service bca4e3
		pfd = npfd;
Packit Service bca4e3
	else
Packit Service bca4e3
		perror("realloc failed");
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
TAILQ_HEAD(iff_list_head, iff);
Packit Service bca4e3
Packit Service bca4e3
struct iff {
Packit Service bca4e3
	int ps;			/* packet socket file descriptor */
Packit Service bca4e3
	int ifindex;
Packit Service bca4e3
	int iflink;
Packit Service bca4e3
	char ifname[IFNAMSIZ];
Packit Service bca4e3
	unsigned char mac_addr[ETHER_ADDR_LEN];
Packit Service bca4e3
	bool running;
Packit Service bca4e3
	bool is_vlan;
Packit Service bca4e3
	short int vid;
Packit Service bca4e3
	bool linkup_sent;
Packit Service bca4e3
	bool req_sent;
Packit Service bca4e3
	bool resp_recv;
Packit Service bca4e3
	bool fip_ready;
Packit Service bca4e3
	bool fcoe_started;
Packit Service bca4e3
	TAILQ_ENTRY(iff) list_node;
Packit Service bca4e3
	struct iff_list_head vlans;
Packit Service bca4e3
};
Packit Service bca4e3
Packit Service bca4e3
struct iff_list_head interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
Packit Service bca4e3
Packit Service bca4e3
TAILQ_HEAD(fcf_list_head, fcf);
Packit Service bca4e3
Packit Service bca4e3
struct fcf {
Packit Service bca4e3
	int ifindex;
Packit Service bca4e3
	uint16_t vlan;
Packit Service bca4e3
	unsigned char mac_addr[ETHER_ADDR_LEN];
Packit Service bca4e3
	TAILQ_ENTRY(fcf) list_node;
Packit Service bca4e3
};
Packit Service bca4e3
Packit Service bca4e3
struct fcf_list_head fcfs = TAILQ_HEAD_INITIALIZER(fcfs);
Packit Service bca4e3
static struct fcf_list_head vn2vns = TAILQ_HEAD_INITIALIZER(vn2vns);
Packit Service bca4e3
Packit Service bca4e3
static int create_and_start_vlan(struct fcf *fcf, bool vn2vn);
Packit Service bca4e3
Packit Service bca4e3
static struct fcf *lookup_fcf(struct fcf_list_head *head, int ifindex,
Packit Service bca4e3
			      uint16_t vlan, unsigned char *mac)
Packit Service bca4e3
{
Packit Service bca4e3
	struct fcf *fcf;
Packit Service bca4e3
Packit Service bca4e3
	TAILQ_FOREACH(fcf, head, list_node)
Packit Service bca4e3
		if ((ifindex == fcf->ifindex) && (vlan == fcf->vlan)) {
Packit Service bca4e3
			if ((!mac) || (memcmp(mac, fcf->mac_addr, ETHER_ADDR_LEN) == 0))
Packit Service bca4e3
				return fcf;
Packit Service bca4e3
		}
Packit Service bca4e3
	return NULL;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static struct iff *lookup_iff(int ifindex, const char *ifname)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
	struct iff *vlan;
Packit Service bca4e3
Packit Service bca4e3
	if (!ifindex && !ifname)
Packit Service bca4e3
		return NULL;
Packit Service bca4e3
Packit Service bca4e3
	TAILQ_FOREACH(iff, &interfaces, list_node) {
Packit Service bca4e3
		if ((!ifindex || ifindex == iff->ifindex) &&
Packit Service bca4e3
		    (!ifname  || strcmp(ifname, iff->ifname) == 0))
Packit Service bca4e3
			return iff;
Packit Service bca4e3
Packit Service bca4e3
		TAILQ_FOREACH(vlan, &iff->vlans, list_node)
Packit Service bca4e3
			if ((!ifindex || ifindex == vlan->ifindex) &&
Packit Service bca4e3
			    (!ifname  || strcmp(ifname, vlan->ifname) == 0))
Packit Service bca4e3
				return vlan;
Packit Service bca4e3
	}
Packit Service bca4e3
	return NULL;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static struct iff *lookup_vlan(int ifindex, short int vid)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *real_dev, *vlan;
Packit Service bca4e3
	TAILQ_FOREACH(real_dev, &interfaces, list_node)
Packit Service bca4e3
		if (real_dev->ifindex == ifindex)
Packit Service bca4e3
			TAILQ_FOREACH(vlan, &real_dev->vlans, list_node)
Packit Service bca4e3
				if (vlan->vid == vid)
Packit Service bca4e3
					return vlan;
Packit Service bca4e3
	return NULL;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static struct iff *find_vlan_real_dev(struct iff *vlan)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *real_dev;
Packit Service bca4e3
	TAILQ_FOREACH(real_dev, &interfaces, list_node) {
Packit Service bca4e3
		if (real_dev->ifindex == vlan->iflink)
Packit Service bca4e3
			return real_dev;
Packit Service bca4e3
	}
Packit Service bca4e3
	return NULL;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
struct fip_tlv_ptrs {
Packit Service bca4e3
	struct fip_tlv_mac_addr		*mac;
Packit Service bca4e3
	struct fip_tlv_vlan		*vlan[370];
Packit Service bca4e3
	unsigned int 			vlanc;
Packit Service bca4e3
};
Packit Service bca4e3
Packit Service bca4e3
#define SET_BIT(b, n)	((b) |= (1 << (n)))
Packit Service bca4e3
Packit Service bca4e3
#define TLV_LEN_CHECK(t, l) ({						\
Packit Service bca4e3
	int _tlc = ((t)->tlv_len != (l)) ? 1 : 0;			\
Packit Service bca4e3
	if (_tlc)							\
Packit Service bca4e3
		FIP_LOG("bad length for TLV of type %d", (t)->tlv_type); \
Packit Service bca4e3
	_tlc;								\
Packit Service bca4e3
	})
Packit Service bca4e3
Packit Service bca4e3
/**
Packit Service bca4e3
 * fip_parse_tlvs - parse type/length/value encoded FIP descriptors
Packit Service bca4e3
 * @ptr: pointer to beginning of FIP TLV payload, the first descriptor
Packit Service bca4e3
 * @len: total length of all TLVs, in double words
Packit Service bca4e3
 * @tlv_ptrs: pointers to type specific structures to fill out
Packit Service bca4e3
 */
Packit Service bca4e3
static unsigned int
Packit Service bca4e3
fip_parse_tlvs(void *ptr, int len, struct fip_tlv_ptrs *tlv_ptrs)
Packit Service bca4e3
{
Packit Service bca4e3
	struct fip_tlv_hdr *tlv = ptr;
Packit Service bca4e3
	unsigned int bitmap = 0;
Packit Service bca4e3
Packit Service bca4e3
	tlv_ptrs->vlanc = 0;
Packit Service bca4e3
	while (len > 0) {
Packit Service bca4e3
		switch (tlv->tlv_type) {
Packit Service bca4e3
		case FIP_TLV_MAC_ADDR:
Packit Service bca4e3
			if (TLV_LEN_CHECK(tlv, 2))
Packit Service bca4e3
				break;
Packit Service bca4e3
			SET_BIT(bitmap, FIP_TLV_MAC_ADDR);
Packit Service bca4e3
			tlv_ptrs->mac = (struct fip_tlv_mac_addr *) tlv;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case FIP_TLV_VLAN:
Packit Service bca4e3
			if (TLV_LEN_CHECK(tlv, 1))
Packit Service bca4e3
				break;
Packit Service bca4e3
			SET_BIT(bitmap, FIP_TLV_VLAN);
Packit Service bca4e3
			tlv_ptrs->vlan[tlv_ptrs->vlanc++] = (void *) tlv;
Packit Service bca4e3
			break;
Packit Service bca4e3
		default:
Packit Service bca4e3
			/* unexpected or unrecognized descriptor */
Packit Service bca4e3
			FIP_LOG("unrecognized TLV type %d", tlv->tlv_type);
Packit Service bca4e3
			break;
Packit Service bca4e3
		}
Packit Service bca4e3
		len -= tlv->tlv_len;
Packit Service bca4e3
		tlv = ((void *) tlv) + (tlv->tlv_len << 2);
Packit Service bca4e3
	};
Packit Service bca4e3
	return bitmap;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
/**
Packit Service bca4e3
 * fip_recv_vlan_note - parse a FIP VLAN Notification
Packit Service bca4e3
 * @fh: FIP header, the beginning of the received FIP frame
Packit Service bca4e3
 * @ifindex: index of interface this was received on
Packit Service bca4e3
 * @vn2vn: true if vn2vn notification
Packit Service bca4e3
 */
Packit Service bca4e3
static int fip_recv_vlan_note(struct fiphdr *fh, int ifindex, bool vn2vn)
Packit Service bca4e3
{
Packit Service bca4e3
	struct fip_tlv_ptrs tlvs;
Packit Service bca4e3
	struct fcf_list_head *head;
Packit Service bca4e3
	struct fcf *fcf;
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
	uint16_t vlan;
Packit Service bca4e3
	unsigned int bitmap, required_tlvs;
Packit Service bca4e3
	int len;
Packit Service bca4e3
	unsigned int i;
Packit Service bca4e3
Packit Service bca4e3
	FIP_LOG_DBG("received FIP VLAN Notification");
Packit Service bca4e3
Packit Service bca4e3
	len = ntohs(fh->fip_desc_len);
Packit Service bca4e3
Packit Service bca4e3
	required_tlvs = (1 << FIP_TLV_MAC_ADDR) | (1 << FIP_TLV_VLAN);
Packit Service bca4e3
Packit Service bca4e3
	tlvs.mac = NULL;	/* Silence incorrect GCC warning */
Packit Service bca4e3
	bitmap = fip_parse_tlvs((fh + 1), len, &tlvs);
Packit Service bca4e3
	if ((bitmap & required_tlvs) != required_tlvs)
Packit Service bca4e3
		return -1;
Packit Service bca4e3
Packit Service bca4e3
	if (vn2vn)
Packit Service bca4e3
		head = &vn2vns;
Packit Service bca4e3
	else
Packit Service bca4e3
		head = &fcf;;
Packit Service bca4e3
Packit Service bca4e3
	iff = lookup_iff(ifindex, NULL);
Packit Service bca4e3
	if (iff)
Packit Service bca4e3
		iff->resp_recv = true;
Packit Service bca4e3
Packit Service bca4e3
	for (i = 0; i < tlvs.vlanc; i++) {
Packit Service bca4e3
		vlan = ntohs(tlvs.vlan[i]->vlan);
Packit Service bca4e3
		if (lookup_fcf(head, ifindex, vlan, tlvs.mac->mac_addr))
Packit Service bca4e3
			continue;
Packit Service bca4e3
Packit Service bca4e3
		fcf = malloc(sizeof(*fcf));
Packit Service bca4e3
		if (!fcf) {
Packit Service bca4e3
			FIP_LOG_ERRNO("malloc failed");
Packit Service bca4e3
			break;
Packit Service bca4e3
		}
Packit Service bca4e3
		memset(fcf, 0, sizeof(*fcf));
Packit Service bca4e3
		fcf->ifindex = ifindex;
Packit Service bca4e3
		fcf->vlan = vlan;
Packit Service bca4e3
		memcpy(fcf->mac_addr, tlvs.mac->mac_addr, ETHER_ADDR_LEN);
Packit Service bca4e3
		TAILQ_INSERT_TAIL(head, fcf, list_node);
Packit Service bca4e3
		if (!config.create)
Packit Service bca4e3
			continue;
Packit Service bca4e3
		create_and_start_vlan(fcf, vn2vn);
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	return 0;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int fip_vlan_handler(struct fiphdr *fh, struct sockaddr_ll *sa,
Packit Service bca4e3
			    UNUSED void *arg)
Packit Service bca4e3
{
Packit Service bca4e3
	/* We only care about VLAN Notifications */
Packit Service bca4e3
	if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) {
Packit Service bca4e3
		FIP_LOG_DBG("ignoring FIP packet, protocol %d",
Packit Service bca4e3
			    ntohs(fh->fip_proto));
Packit Service bca4e3
		return -1;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	switch (fh->fip_subcode) {
Packit Service bca4e3
	case FIP_VLAN_NOTE:
Packit Service bca4e3
		if (config.vn2vn) {
Packit Service bca4e3
			FIP_LOG_DBG("ignoring FCF response in vn2vn mode\n");
Packit Service bca4e3
			return -1;
Packit Service bca4e3
		}
Packit Service bca4e3
		return fip_recv_vlan_note(fh, sa->sll_ifindex, false);
Packit Service bca4e3
	case FIP_VLAN_NOTE_VN2VN:
Packit Service bca4e3
		if (!config.vn2vn) {
Packit Service bca4e3
			FIP_LOG_DBG("ignoring VN2VN response in fabric mode\n");
Packit Service bca4e3
			return -1;
Packit Service bca4e3
		}
Packit Service bca4e3
		return fip_recv_vlan_note(fh, sa->sll_ifindex, true);
Packit Service bca4e3
	default:
Packit Service bca4e3
		FIP_LOG_DBG("ignored FIP VLAN packet with subcode %d",
Packit Service bca4e3
			    fh->fip_subcode);
Packit Service bca4e3
		return -1;
Packit Service bca4e3
	}
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
/**
Packit Service bca4e3
 * rtnl_recv_newlink - parse response to RTM_GETLINK, or an RTM_NEWLINK event
Packit Service bca4e3
 * @nh: netlink message header, beginning of received netlink frame
Packit Service bca4e3
 */
Packit Service bca4e3
static void rtnl_recv_newlink(struct nlmsghdr *nh)
Packit Service bca4e3
{
Packit Service bca4e3
	struct ifinfomsg *ifm = NLMSG_DATA(nh);
Packit Service bca4e3
	struct rtattr *ifla[__IFLA_MAX];
Packit Service bca4e3
	struct rtattr *linkinfo[__IFLA_INFO_MAX];
Packit Service bca4e3
	struct rtattr *vlan[__IFLA_VLAN_MAX];
Packit Service bca4e3
	struct iff *iff, *real_dev;
Packit Service bca4e3
	struct fcf_list_head *head;
Packit Service bca4e3
	bool running;
Packit Service bca4e3
Packit Service bca4e3
	if (config.vn2vn)
Packit Service bca4e3
		head = &vn2vns;
Packit Service bca4e3
	else
Packit Service bca4e3
		head = &fcf;;
Packit Service bca4e3
Packit Service bca4e3
	FIP_LOG_DBG("RTM_NEWLINK: ifindex %d, type %d, flags %x",
Packit Service bca4e3
		    ifm->ifi_index, ifm->ifi_type, ifm->ifi_flags);
Packit Service bca4e3
Packit Service bca4e3
	/* We only deal with Ethernet interfaces */
Packit Service bca4e3
	if (ifm->ifi_type != ARPHRD_ETHER)
Packit Service bca4e3
		return;
Packit Service bca4e3
Packit Service bca4e3
	/* not on bond master, but rather allow FIP on the slaves below */
Packit Service bca4e3
	if (ifm->ifi_flags & IFF_MASTER)
Packit Service bca4e3
		return;
Packit Service bca4e3
Packit Service bca4e3
	running = !!(ifm->ifi_flags & (IFF_RUNNING | IFF_SLAVE));
Packit Service bca4e3
	iff = lookup_iff(ifm->ifi_index, NULL);
Packit Service bca4e3
	if (iff) {
Packit Service bca4e3
		int ifindex;
Packit Service bca4e3
Packit Service bca4e3
		/* already tracking, update operstate and return */
Packit Service bca4e3
		iff->running = running;
Packit Service bca4e3
		if (!iff->running) {
Packit Service bca4e3
			pfd_remove(iff->ps);
Packit Service bca4e3
			return;
Packit Service bca4e3
		}
Packit Service bca4e3
		pfd_add(iff->ps);
Packit Service bca4e3
		if (!config.start)
Packit Service bca4e3
			return;
Packit Service bca4e3
Packit Service bca4e3
		FIP_LOG_DBG("Checking for FCoE on %sif %d",
Packit Service bca4e3
			    iff->is_vlan ? "VLAN " : "", iff->ifindex);
Packit Service bca4e3
		if (iff->is_vlan) {
Packit Service bca4e3
			real_dev = find_vlan_real_dev(iff);
Packit Service bca4e3
			if (!real_dev) {
Packit Service bca4e3
				FIP_LOG_ERR(ENODEV, "VLAN %d without a parent",
Packit Service bca4e3
					    iff->ifindex);
Packit Service bca4e3
				return;
Packit Service bca4e3
			}
Packit Service bca4e3
			ifindex = real_dev->ifindex;
Packit Service bca4e3
		} else
Packit Service bca4e3
			ifindex = iff->ifindex;
Packit Service bca4e3
Packit Service bca4e3
		if (!iff->fcoe_started &&
Packit Service bca4e3
		    lookup_fcf(head, ifindex, iff->vid, NULL)) {
Packit Service bca4e3
			printf("Starting FCoE on interface %s\n",
Packit Service bca4e3
			       iff->ifname);
Packit Service bca4e3
			fcoe_instance_start(iff->ifname);
Packit Service bca4e3
			iff->fcoe_started = true;
Packit Service bca4e3
		}
Packit Service bca4e3
		return;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	iff = malloc(sizeof(*iff));
Packit Service bca4e3
	if (!iff) {
Packit Service bca4e3
		FIP_LOG_ERRNO("malloc failed");
Packit Service bca4e3
		return;
Packit Service bca4e3
	}
Packit Service bca4e3
	memset(iff, 0, sizeof(*iff));
Packit Service bca4e3
	TAILQ_INIT(&iff->vlans);
Packit Service bca4e3
Packit Service bca4e3
	parse_ifinfo(ifla, nh);
Packit Service bca4e3
Packit Service bca4e3
	iff->ifindex = ifm->ifi_index;
Packit Service bca4e3
	iff->running = running;
Packit Service bca4e3
	iff->fip_ready = false;
Packit Service bca4e3
	if (ifla[IFLA_LINK])
Packit Service bca4e3
		iff->iflink = *(int *)RTA_DATA(ifla[IFLA_LINK]);
Packit Service bca4e3
	else
Packit Service bca4e3
		iff->iflink = iff->ifindex;
Packit Service bca4e3
	memcpy(iff->mac_addr, RTA_DATA(ifla[IFLA_ADDRESS]), ETHER_ADDR_LEN);
Packit Service bca4e3
	strncpy(iff->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
Packit Service bca4e3
	iff->ifname[IFNAMSIZ - 1] = '\0';
Packit Service bca4e3
Packit Service bca4e3
	if (ifla[IFLA_LINKINFO]) {
Packit Service bca4e3
		parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]);
Packit Service bca4e3
		/* Track VLAN devices separately */
Packit Service bca4e3
		if (linkinfo[IFLA_INFO_KIND] &&
Packit Service bca4e3
		    !strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan")) {
Packit Service bca4e3
			iff->is_vlan = true;
Packit Service bca4e3
			parse_vlaninfo(vlan, linkinfo[IFLA_INFO_DATA]);
Packit Service bca4e3
			iff->vid = *(int *)RTA_DATA(vlan[IFLA_VLAN_ID]);
Packit Service bca4e3
			real_dev = find_vlan_real_dev(iff);
Packit Service bca4e3
			if (!real_dev) {
Packit Service bca4e3
				free(iff);
Packit Service bca4e3
				return;
Packit Service bca4e3
			}
Packit Service bca4e3
			TAILQ_INSERT_TAIL(&real_dev->vlans, iff, list_node);
Packit Service bca4e3
			if (!iff->running) {
Packit Service bca4e3
				FIP_LOG_DBG("vlan if %d not running, "
Packit Service bca4e3
					    "starting", iff->ifindex);
Packit Service bca4e3
				rtnl_set_iff_up(iff->ifindex, NULL);
Packit Service bca4e3
			}
Packit Service bca4e3
			return;
Packit Service bca4e3
		}
Packit Service bca4e3
		/* ignore bonding interfaces */
Packit Service bca4e3
		if (linkinfo[IFLA_INFO_KIND] &&
Packit Service bca4e3
		    !strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "bond")) {
Packit Service bca4e3
			free(iff);
Packit Service bca4e3
			return;
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
	TAILQ_INSERT_TAIL(&interfaces, iff, list_node);
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
/* command line arguments */
Packit Service bca4e3
Packit Service bca4e3
#define GETOPT_STR "acdf:l:m:suhv"
Packit Service bca4e3
Packit Service bca4e3
static const struct option long_options[] = {
Packit Service bca4e3
	{ "auto", no_argument, NULL, 'a' },
Packit Service bca4e3
	{ "create", no_argument, NULL, 'c' },
Packit Service bca4e3
	{ "start", no_argument, NULL, 's' },
Packit Service bca4e3
	{ "debug", no_argument, NULL, 'd' },
Packit Service bca4e3
	{ "suffix", required_argument, NULL, 'f' },
Packit Service bca4e3
	{ "link-retry", required_argument, NULL, 'l' },
Packit Service bca4e3
	{ "mode", required_argument, NULL, 'm' },
Packit Service bca4e3
	{ "link-up", required_argument, NULL, 'u' },
Packit Service bca4e3
	{ "help", no_argument, NULL, 'h' },
Packit Service bca4e3
	{ "version", no_argument, NULL, 'v' },
Packit Service bca4e3
	{ NULL, 0, NULL, 0 }
Packit Service bca4e3
};
Packit Service bca4e3
Packit Service bca4e3
static void help(int status)
Packit Service bca4e3
{
Packit Service bca4e3
	printf(
Packit Service bca4e3
		"Usage: %s [ options ] [ network interfaces ]\n"
Packit Service bca4e3
		"Options:\n"
Packit Service bca4e3
		"  -a, --auto           Auto select Ethernet interfaces\n"
Packit Service bca4e3
		"  -c, --create         Create system VLAN devices\n"
Packit Service bca4e3
		"  -d, --debug          Enable debugging output\n"
Packit Service bca4e3
		"  -s, --start          Start FCoE login automatically\n"
Packit Service bca4e3
		"  -f, --suffix		Append the suffix to VLAN interface name\n"
Packit Service bca4e3
		"  -l, --link-retry     Number of retries for link up\n"
Packit Service bca4e3
		"  -m, --mode           Link mode, either fabric or vn2vn\n"
Packit Service bca4e3
		"  -u, --link-up        Leave link up after FIP response\n"
Packit Service bca4e3
		"  -h, --help           Display this help and exit\n"
Packit Service bca4e3
		"  -v, --version        Display version information and exit\n",
Packit Service bca4e3
		exe);
Packit Service bca4e3
Packit Service bca4e3
	exit(status);
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void parse_cmdline(int argc, char **argv)
Packit Service bca4e3
{
Packit Service bca4e3
	signed char c;
Packit Service bca4e3
Packit Service bca4e3
	while (1) {
Packit Service bca4e3
		c = getopt_long(argc, argv, GETOPT_STR, long_options, NULL);
Packit Service bca4e3
		if (c < 0)
Packit Service bca4e3
			break;
Packit Service bca4e3
		switch (c) {
Packit Service bca4e3
		case 'a':
Packit Service bca4e3
			config.automode = true;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'c':
Packit Service bca4e3
			config.create = true;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'd':
Packit Service bca4e3
			config.debug = true;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 's':
Packit Service bca4e3
			config.start = true;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'f':
Packit Service bca4e3
			if (optarg && strlen(optarg)) {
Packit Service bca4e3
				strncpy(config.suffix, optarg, 256);
Packit Service bca4e3
				config.suffix[256 - 1] = '\0';
Packit Service bca4e3
			}
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'l':
Packit Service bca4e3
			config.link_retry = strtoul(optarg, NULL, 10);
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'm':
Packit Service bca4e3
			if (strcasecmp(optarg, "vn2vn") == 0)
Packit Service bca4e3
				config.vn2vn = true;
Packit Service bca4e3
			else if (strcasecmp(optarg, "fabric") == 0)
Packit Service bca4e3
				config.vn2vn = false;
Packit Service bca4e3
			else {
Packit Service bca4e3
				fprintf(stderr, "%s: Unknown value for mode: %s\n",
Packit Service bca4e3
					exe, optarg);
Packit Service bca4e3
				exit(1);
Packit Service bca4e3
			}
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'u':
Packit Service bca4e3
			config.link_up = true;
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'h':
Packit Service bca4e3
			help(0);
Packit Service bca4e3
			break;
Packit Service bca4e3
		case 'v':
Packit Service bca4e3
			printf("%s version %s\n", exe, FCOE_UTILS_VERSION);
Packit Service bca4e3
			exit(0);
Packit Service bca4e3
			break;
Packit Service bca4e3
		default:
Packit Service bca4e3
			fprintf(stderr, "Try '%s --help' "
Packit Service bca4e3
				"for more information\n", exe);
Packit Service bca4e3
			exit(1);
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if ((optind == argc) && (!config.automode))
Packit Service bca4e3
		help(1);
Packit Service bca4e3
Packit Service bca4e3
	config.namev = &argv[optind];
Packit Service bca4e3
	config.namec = argc - optind;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int rtnl_listener_handler(struct nlmsghdr *nh, UNUSED void *arg)
Packit Service bca4e3
{
Packit Service bca4e3
	switch (nh->nlmsg_type) {
Packit Service bca4e3
	case RTM_NEWLINK:
Packit Service bca4e3
		rtnl_recv_newlink(nh);
Packit Service bca4e3
		return 0;
Packit Service bca4e3
	}
Packit Service bca4e3
	return -1;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int
Packit Service bca4e3
safe_makevlan_name(char *vlan_name, size_t vsz,
Packit Service bca4e3
		char *ifname, int vlan_num, char *suffix)
Packit Service bca4e3
{
Packit Service bca4e3
	size_t ifsz = strlen(ifname);
Packit Service bca4e3
	size_t susz = strlen(suffix);	/* should never be NULL */
Packit Service bca4e3
	int nusz;
Packit Service bca4e3
	char numbuf[16];
Packit Service bca4e3
	char *cp = vlan_name;
Packit Service bca4e3
Packit Service bca4e3
	nusz = snprintf(numbuf, sizeof(numbuf), "%d", vlan_num);
Packit Service bca4e3
Packit Service bca4e3
	if ((ifsz + susz + nusz + 2) > vsz) {
Packit Service bca4e3
		FIP_LOG_ERR(EINVAL,
Packit Service bca4e3
			"Cannot make VLAN name from ifname=\"%s\", vlan %d, and suffix=\"%s\"\n",
Packit Service bca4e3
			ifname, vlan_num, suffix);
Packit Service bca4e3
		return -EINVAL;
Packit Service bca4e3
	}
Packit Service bca4e3
	memcpy(cp, ifname, ifsz);
Packit Service bca4e3
	cp += ifsz;
Packit Service bca4e3
	memcpy(cp, numbuf, nusz);
Packit Service bca4e3
	cp += nusz;
Packit Service bca4e3
	if (susz > 0) {
Packit Service bca4e3
		memcpy(cp, suffix, susz);
Packit Service bca4e3
		cp += susz;
Packit Service bca4e3
	}
Packit Service bca4e3
	*cp = '\0';
Packit Service bca4e3
	return 0;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int
Packit Service bca4e3
create_and_start_vlan(struct fcf *fcf, bool vn2vn)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *real_dev, *vlan;
Packit Service bca4e3
	char vlan_name[IFNAMSIZ];
Packit Service bca4e3
	int rc;
Packit Service bca4e3
Packit Service bca4e3
	real_dev = lookup_iff(fcf->ifindex, NULL);
Packit Service bca4e3
	if (!real_dev) {
Packit Service bca4e3
		FIP_LOG_ERR(ENODEV,
Packit Service bca4e3
			    "lost device %d with discovered %s?\n",
Packit Service bca4e3
			    fcf->ifindex, vn2vn ? "VN2VN" : "FCF");
Packit Service bca4e3
		return -ENXIO;
Packit Service bca4e3
	}
Packit Service bca4e3
	if (!fcf->vlan) {
Packit Service bca4e3
		/*
Packit Service bca4e3
		 * If the vlan notification has VLAN id 0,
Packit Service bca4e3
		 * skip creating vlan interface, and FCoE is
Packit Service bca4e3
		 * started on the physical interface itself.
Packit Service bca4e3
		 */
Packit Service bca4e3
		FIP_LOG_DBG("VLAN id is 0 for %s\n", real_dev->ifname);
Packit Service bca4e3
		vlan = real_dev;
Packit Service bca4e3
	} else {
Packit Service bca4e3
		vlan = lookup_vlan(fcf->ifindex, fcf->vlan);
Packit Service bca4e3
		if (vlan) {
Packit Service bca4e3
			FIP_LOG_DBG("VLAN %s.%d already exists as %s\n",
Packit Service bca4e3
				    real_dev->ifname, fcf->vlan, vlan->ifname);
Packit Service bca4e3
			rc = 0;
Packit Service bca4e3
		} else {
Packit Service bca4e3
			rc = safe_makevlan_name(vlan_name, sizeof(vlan_name),
Packit Service bca4e3
				 real_dev->ifname, fcf->vlan, config.suffix);
Packit Service bca4e3
			if (rc < 0)
Packit Service bca4e3
				return rc;
Packit Service bca4e3
			rc = vlan_create(fcf->ifindex, fcf->vlan, vlan_name);
Packit Service bca4e3
			if (rc < 0)
Packit Service bca4e3
				printf("Failed to create VLAN device %s\n\t%s\n",
Packit Service bca4e3
				       vlan_name, strerror(-rc));
Packit Service bca4e3
			else
Packit Service bca4e3
				printf("Created VLAN device %s\n", vlan_name);
Packit Service bca4e3
			return rc;
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
	if (!config.start)
Packit Service bca4e3
		return rc;
Packit Service bca4e3
Packit Service bca4e3
	if (!vlan->running) {
Packit Service bca4e3
		FIP_LOG_DBG("%s if %d not running, starting",
Packit Service bca4e3
			    vlan == real_dev ? "real" : "vlan",
Packit Service bca4e3
			    vlan->ifindex);
Packit Service bca4e3
		rtnl_set_iff_up(vlan->ifindex, NULL);
Packit Service bca4e3
	} else if (!vlan->fcoe_started) {
Packit Service bca4e3
		printf("Starting FCoE on interface %s\n",
Packit Service bca4e3
		       vlan->ifname);
Packit Service bca4e3
		fcoe_instance_start(vlan->ifname);
Packit Service bca4e3
		vlan->fcoe_started = true;
Packit Service bca4e3
	}
Packit Service bca4e3
	return rc;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int fcoe_mod_instance_start(const char *ifname)
Packit Service bca4e3
{
Packit Service bca4e3
	enum fcoe_status ret;
Packit Service bca4e3
	const char *path;
Packit Service bca4e3
Packit Service bca4e3
	if (config.vn2vn)
Packit Service bca4e3
		path = FCOE_CREATE_VN2VN;
Packit Service bca4e3
	else
Packit Service bca4e3
		path = FCOE_CREATE;
Packit Service bca4e3
Packit Service bca4e3
	ret = fcm_write_str_to_sysfs_file(path, ifname);
Packit Service bca4e3
	if (ret) {
Packit Service bca4e3
		FIP_LOG_ERRNO("Failed to open file: %s", FCOE_CREATE);
Packit Service bca4e3
		FIP_LOG_ERRNO("May be fcoe stack not loaded, starting"
Packit Service bca4e3
			      " fcoe service will fix that");
Packit Service bca4e3
Packit Service bca4e3
		return EFAIL;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	return 0;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int fcoe_bus_instance_start(const char *ifname)
Packit Service bca4e3
{
Packit Service bca4e3
	enum fcoe_status ret;
Packit Service bca4e3
	char fchost[FCHOSTBUFLEN];
Packit Service bca4e3
	char ctlr[FCHOSTBUFLEN];
Packit Service bca4e3
Packit Service bca4e3
	ret = fcm_write_str_to_sysfs_file(FCOE_BUS_CREATE, ifname);
Packit Service bca4e3
	if (ret) {
Packit Service bca4e3
		FIP_LOG_ERRNO("Failed to open file: %s", FCOE_BUS_CREATE);
Packit Service bca4e3
		FIP_LOG_ERRNO("May be fcoe stack not loaded, starting"
Packit Service bca4e3
			      " fcoe service will fix that");
Packit Service bca4e3
		return ret;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if (fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN)) {
Packit Service bca4e3
		FIP_LOG_DBG("Failed to find fc_host for %s\n", ifname);
Packit Service bca4e3
		return ENOSYSFS;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if (fcoe_find_ctlr(fchost, ctlr, FCHOSTBUFLEN)) {
Packit Service bca4e3
		FIP_LOG_DBG("Failed to get ctlr for %s\n", ifname);
Packit Service bca4e3
		return ENOSYSFS;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if (config.vn2vn) {
Packit Service bca4e3
		ret = fcm_write_str_to_ctlr_attr(ctlr, FCOE_CTLR_ATTR_MODE,
Packit Service bca4e3
						 "vn2vn");
Packit Service bca4e3
		if (ret)
Packit Service bca4e3
			FIP_LOG_DBG("Failed to set mode interface %s\n",
Packit Service bca4e3
				    ifname);
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	ret = fcm_write_str_to_ctlr_attr(ctlr, FCOE_CTLR_ATTR_ENABLED, "1");
Packit Service bca4e3
	if (ret)
Packit Service bca4e3
		FIP_LOG_DBG("Failed to enable interface %s\n", ifname);
Packit Service bca4e3
Packit Service bca4e3
	return 0;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void determine_libfcoe_interface(void)
Packit Service bca4e3
{
Packit Service bca4e3
	if (!access(FCOE_BUS_CREATE, F_OK)) {
Packit Service bca4e3
		FIP_LOG_DBG("Using /sys/bus/fcoe interfaces\n");
Packit Service bca4e3
		fcoe_instance_start = &fcoe_bus_instance_start;
Packit Service bca4e3
	} else {
Packit Service bca4e3
		FIP_LOG_DBG("Using libfcoe module parameter interfaces\n");
Packit Service bca4e3
		fcoe_instance_start = &fcoe_mod_instance_start;
Packit Service bca4e3
	}
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void print_list(struct fcf_list_head *list, const char *label)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
	struct fcf *fcf;
Packit Service bca4e3
Packit Service bca4e3
	printf("%-16.16s| %-5.5s| %-17.17s\n", "interface", "VLAN", label);
Packit Service bca4e3
	printf("------------------------------------------\n");
Packit Service bca4e3
	TAILQ_FOREACH(fcf, list, list_node) {
Packit Service bca4e3
		iff = lookup_iff(fcf->ifindex, NULL);
Packit Service bca4e3
		printf("%-16.16s| %-5d| %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
Packit Service bca4e3
		       iff->ifname, fcf->vlan,
Packit Service bca4e3
		       fcf->mac_addr[0], fcf->mac_addr[1], fcf->mac_addr[2],
Packit Service bca4e3
		       fcf->mac_addr[3], fcf->mac_addr[4], fcf->mac_addr[5]);
Packit Service bca4e3
	}
Packit Service bca4e3
	printf("\n");
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int print_results(void)
Packit Service bca4e3
{
Packit Service bca4e3
	if (TAILQ_EMPTY(&fcfs) && TAILQ_EMPTY(&vn2vns)) {
Packit Service bca4e3
		printf("No Fibre Channel Forwarders or VN2VN Responders Found\n");
Packit Service bca4e3
		return ENODEV;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if (!TAILQ_EMPTY(&fcfs)) {
Packit Service bca4e3
		printf("Fibre Channel Forwarders Discovered\n");
Packit Service bca4e3
		print_list(&fcfs, "FCF MAC");
Packit Service bca4e3
	}
Packit Service bca4e3
	if (!TAILQ_EMPTY(&vn2vns)) {
Packit Service bca4e3
		printf("VN2VN Responders Discovered\n");
Packit Service bca4e3
		print_list(&vn2vns, "VN2VN MAC");
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	return 0;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void recv_loop(int timeout)
Packit Service bca4e3
{
Packit Service bca4e3
	int i;
Packit Service bca4e3
	int rc;
Packit Service bca4e3
Packit Service bca4e3
	while (1) {
Packit Service bca4e3
		rc = poll(pfd, pfd_len, timeout);
Packit Service bca4e3
		FIP_LOG_DBG("return from poll %d", rc);
Packit Service bca4e3
		if (rc == 0) /* timeout */
Packit Service bca4e3
			break;
Packit Service bca4e3
		if (rc == -1) {
Packit Service bca4e3
			FIP_LOG_ERRNO("poll error");
Packit Service bca4e3
			break;
Packit Service bca4e3
		}
Packit Service bca4e3
		/* pfd[0] must be the netlink socket */
Packit Service bca4e3
		if (pfd[0].revents & POLLIN)
Packit Service bca4e3
			rtnl_recv(pfd[0].fd, rtnl_listener_handler, NULL);
Packit Service bca4e3
		/* everything else should be FIP packet sockets */
Packit Service bca4e3
		for (i = 1; i < pfd_len; i++) {
Packit Service bca4e3
			if (pfd[i].revents & POLLIN) {
Packit Service bca4e3
				rc = fip_recv(pfd[i].fd, fip_vlan_handler,
Packit Service bca4e3
					      NULL);
Packit Service bca4e3
				if (rc < 0)
Packit Service bca4e3
					break;
Packit Service bca4e3
			}
Packit Service bca4e3
		}
Packit Service bca4e3
		if (i < pfd_len)
Packit Service bca4e3
			break;
Packit Service bca4e3
	}
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void find_interfaces(int ns)
Packit Service bca4e3
{
Packit Service bca4e3
	send_getlink_dump(ns);
Packit Service bca4e3
	rtnl_recv(ns, rtnl_listener_handler, NULL);
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int probe_fip_interface(struct iff *iff)
Packit Service bca4e3
{
Packit Service bca4e3
	int origdev = 1, rc;
Packit Service bca4e3
Packit Service bca4e3
	if (iff->resp_recv)
Packit Service bca4e3
		return 0;
Packit Service bca4e3
	if (!iff->running) {
Packit Service bca4e3
		if (iff->linkup_sent) {
Packit Service bca4e3
			FIP_LOG_DBG("if %d not running, waiting for link up",
Packit Service bca4e3
				    iff->ifindex);
Packit Service bca4e3
		} else {
Packit Service bca4e3
			FIP_LOG_DBG("if %d not running, starting",
Packit Service bca4e3
				    iff->ifindex);
Packit Service bca4e3
			rtnl_set_iff_up(iff->ifindex, NULL);
Packit Service bca4e3
			iff->linkup_sent = true;
Packit Service bca4e3
		}
Packit Service bca4e3
		iff->req_sent = false;
Packit Service bca4e3
		return 1;
Packit Service bca4e3
	}
Packit Service bca4e3
	if (iff->req_sent)
Packit Service bca4e3
		return 0;
Packit Service bca4e3
Packit Service bca4e3
	if (!iff->fip_ready) {
Packit Service bca4e3
		iff->ps = fip_socket(iff->ifindex, iff->mac_addr, FIP_NONE);
Packit Service bca4e3
		if (iff->ps < 0) {
Packit Service bca4e3
			FIP_LOG_DBG("if %d not ready\n", iff->ifindex);
Packit Service bca4e3
			return 0;
Packit Service bca4e3
		}
Packit Service bca4e3
		setsockopt(iff->ps, SOL_PACKET, PACKET_ORIGDEV,
Packit Service bca4e3
			   &origdev, sizeof(origdev));
Packit Service bca4e3
		pfd_add(iff->ps);
Packit Service bca4e3
		iff->fip_ready = true;
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	if (config.vn2vn)
Packit Service bca4e3
		rc = fip_send_vlan_request(iff->ps, iff->ifindex,
Packit Service bca4e3
					   iff->mac_addr, FIP_ALL_VN2VN);
Packit Service bca4e3
	else
Packit Service bca4e3
		rc = fip_send_vlan_request(iff->ps, iff->ifindex,
Packit Service bca4e3
					   iff->mac_addr, FIP_ALL_FCF);
Packit Service bca4e3
	if (rc == 0)
Packit Service bca4e3
		iff->req_sent = true;
Packit Service bca4e3
	return rc == 0 ? 0 : 1;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int send_vlan_requests(void)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
	int skipped = 0;
Packit Service bca4e3
	int i;
Packit Service bca4e3
Packit Service bca4e3
	if (config.automode) {
Packit Service bca4e3
		TAILQ_FOREACH(iff, &interfaces, list_node) {
Packit Service bca4e3
			skipped += probe_fip_interface(iff);
Packit Service bca4e3
		}
Packit Service bca4e3
	} else {
Packit Service bca4e3
		for (i = 0; i < config.namec; i++) {
Packit Service bca4e3
			iff = lookup_iff(0, config.namev[i]);
Packit Service bca4e3
			if (!iff) {
Packit Service bca4e3
				skipped++;
Packit Service bca4e3
				continue;
Packit Service bca4e3
			}
Packit Service bca4e3
			skipped += probe_fip_interface(iff);
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
	return skipped;
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void do_vlan_discovery(void)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
	int retry_count = 0;
Packit Service bca4e3
	int skip_retry_count = 0;
Packit Service bca4e3
	int skipped = 0, retry_iff = 0;
Packit Service bca4e3
retry:
Packit Service bca4e3
	skipped += send_vlan_requests();
Packit Service bca4e3
	if (skipped && skip_retry_count++ < config.link_retry) {
Packit Service bca4e3
		FIP_LOG_DBG("waiting for IFF_RUNNING [%d/%d]\n",
Packit Service bca4e3
			    skip_retry_count, config.link_retry);
Packit Service bca4e3
		recv_loop(500);
Packit Service bca4e3
		skipped = 0;
Packit Service bca4e3
		retry_count = 0;
Packit Service bca4e3
		goto retry;
Packit Service bca4e3
	}
Packit Service bca4e3
	recv_loop(200);
Packit Service bca4e3
	TAILQ_FOREACH(iff, &interfaces, list_node) {
Packit Service bca4e3
		if (!iff->fip_ready) {
Packit Service bca4e3
			FIP_LOG_DBG("if %d: skipping, FIP not ready\n",
Packit Service bca4e3
				    iff->ifindex);
Packit Service bca4e3
			continue;
Packit Service bca4e3
		}
Packit Service bca4e3
		if (!iff->running && iff->linkup_sent) {
Packit Service bca4e3
			FIP_LOG_DBG("if %d: waiting for IFF_RUNNING [%d]\n",
Packit Service bca4e3
				    iff->ifindex, retry_count);
Packit Service bca4e3
			retry_iff++;
Packit Service bca4e3
			continue;
Packit Service bca4e3
		}
Packit Service bca4e3
		/* if we did not receive a response, retry */
Packit Service bca4e3
		if (iff->req_sent && !iff->resp_recv) {
Packit Service bca4e3
			FIP_LOG_DBG("if %d: VLAN discovery RETRY [%d]",
Packit Service bca4e3
				    iff->ifindex, retry_count);
Packit Service bca4e3
			iff->req_sent = false;
Packit Service bca4e3
			retry_iff++;
Packit Service bca4e3
			continue;
Packit Service bca4e3
		}
Packit Service bca4e3
		if (config.create) {
Packit Service bca4e3
			struct iff *vlan;
Packit Service bca4e3
Packit Service bca4e3
			TAILQ_FOREACH(vlan, &iff->vlans, list_node) {
Packit Service bca4e3
				if (!vlan->running) {
Packit Service bca4e3
					FIP_LOG_DBG("vlan %d: waiting for "
Packit Service bca4e3
						    "IFF_RUNNING [%d]",
Packit Service bca4e3
						    vlan->ifindex, retry_count);
Packit Service bca4e3
					retry_iff++;
Packit Service bca4e3
					continue;
Packit Service bca4e3
				}
Packit Service bca4e3
			}
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
	if (retry_iff && retry_count++ < config.link_retry) {
Packit Service bca4e3
		recv_loop(1000);
Packit Service bca4e3
		retry_iff = 0;
Packit Service bca4e3
		goto retry;
Packit Service bca4e3
	}
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static void cleanup_interfaces(void)
Packit Service bca4e3
{
Packit Service bca4e3
	struct iff *iff;
Packit Service bca4e3
Packit Service bca4e3
	TAILQ_FOREACH(iff, &interfaces, list_node) {
Packit Service bca4e3
		if (iff->linkup_sent) {
Packit Service bca4e3
			if (config.link_up && iff->resp_recv)
Packit Service bca4e3
				continue;
Packit Service bca4e3
			if (iff->fcoe_started)
Packit Service bca4e3
				continue;
Packit Service bca4e3
			if (TAILQ_EMPTY(&iff->vlans)) {
Packit Service bca4e3
				FIP_LOG_DBG("shutdown if %d",
Packit Service bca4e3
					    iff->ifindex);
Packit Service bca4e3
				rtnl_set_iff_down(iff->ifindex, NULL);
Packit Service bca4e3
				iff->linkup_sent = false;
Packit Service bca4e3
			}
Packit Service bca4e3
		}
Packit Service bca4e3
	}
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
/* this is to not require headers from libcap */
Packit Service bca4e3
static inline int capget(cap_user_header_t hdrp, cap_user_data_t datap)
Packit Service bca4e3
{
Packit Service bca4e3
	return syscall(__NR_capget, hdrp, datap);
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
static int checkcaps(void)
Packit Service bca4e3
{
Packit Service bca4e3
	struct __user_cap_header_struct caphdr = {
Packit Service bca4e3
		.version = _LINUX_CAPABILITY_VERSION_3,
Packit Service bca4e3
		.pid = 0,
Packit Service bca4e3
	};
Packit Service bca4e3
	struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
Packit Service bca4e3
Packit Service bca4e3
	capget(&caphdr, caps);
Packit Service bca4e3
	return !(caps[CAP_TO_INDEX(CAP_NET_RAW)].effective &
Packit Service bca4e3
		 CAP_TO_MASK(CAP_NET_RAW));
Packit Service bca4e3
}
Packit Service bca4e3
Packit Service bca4e3
int main(int argc, char **argv)
Packit Service bca4e3
{
Packit Service bca4e3
	int ns;
Packit Service bca4e3
	int rc = 0;
Packit Service bca4e3
	int find_cnt = 0;
Packit Service bca4e3
Packit Service bca4e3
	exe = strrchr(argv[0], '/');
Packit Service bca4e3
	if (exe)
Packit Service bca4e3
		exe++;
Packit Service bca4e3
	else
Packit Service bca4e3
		exe = argv[0];
Packit Service bca4e3
Packit Service bca4e3
	parse_cmdline(argc, argv);
Packit Service bca4e3
	sa_log_prefix = exe;
Packit Service bca4e3
	sa_log_flags = 0;
Packit Service bca4e3
	enable_debug_log(config.debug);
Packit Service bca4e3
Packit Service bca4e3
	if (checkcaps()) {
Packit Service bca4e3
		FIP_LOG("must run as root or with the NET_RAW capability");
Packit Service bca4e3
		exit(1);
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	ns = rtnl_socket(RTMGRP_LINK);
Packit Service bca4e3
	if (ns < 0) {
Packit Service bca4e3
		rc = 1;
Packit Service bca4e3
		goto ns_err;
Packit Service bca4e3
	}
Packit Service bca4e3
	pfd_add(ns);
Packit Service bca4e3
Packit Service bca4e3
	determine_libfcoe_interface();
Packit Service bca4e3
Packit Service bca4e3
	find_interfaces(ns);
Packit Service bca4e3
	if (config.automode)
Packit Service bca4e3
		while ((TAILQ_EMPTY(&interfaces)) && ++find_cnt < 5) {
Packit Service bca4e3
			FIP_LOG_DBG("no interfaces found, trying again");
Packit Service bca4e3
			find_interfaces(ns);
Packit Service bca4e3
		}
Packit Service bca4e3
Packit Service bca4e3
	if (TAILQ_EMPTY(&interfaces)) {
Packit Service bca4e3
		if (config.automode)
Packit Service bca4e3
			FIP_LOG_ERR(ENODEV,
Packit Service bca4e3
				    "no interfaces to perform discovery on");
Packit Service bca4e3
		else
Packit Service bca4e3
			FIP_LOG("no interfaces to perform discovery on");
Packit Service bca4e3
		exit(ENODEV);
Packit Service bca4e3
	}
Packit Service bca4e3
Packit Service bca4e3
	do_vlan_discovery();
Packit Service bca4e3
Packit Service bca4e3
	rc = print_results();
Packit Service bca4e3
Packit Service bca4e3
	cleanup_interfaces();
Packit Service bca4e3
Packit Service bca4e3
	close(ns);
Packit Service bca4e3
ns_err:
Packit Service bca4e3
	exit(rc);
Packit Service bca4e3
}
Packit Service bca4e3