From 277b5f3503d0e4fbf76b1853ef85bdc8ca0163f24cc03aeada17ea521f4b6708 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 19 Nov 2013 11:56:09 +0000 Subject: [PATCH 1/2] - Update to latest git version: * VPD22 support * Netlink fixes OBS-URL: https://build.opensuse.org/package/show/network:fcoe/open-lldp?expand=0&rev=9 --- open-lldp-git-update.patch | 1273 +++++++++++++++++++++++++++++++----- open-lldp.changes | 7 + 2 files changed, 1106 insertions(+), 174 deletions(-) diff --git a/open-lldp-git-update.patch b/open-lldp-git-update.patch index 3aa9d74..1a7c6c9 100644 --- a/open-lldp-git-update.patch +++ b/open-lldp-git-update.patch @@ -12,7 +12,7 @@ index 5f297e5..87eef25 100644 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/Makefile.am b/Makefile.am -index 893fa45..85ee213 100644 +index 893fa45..4b07191 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ include/clif.h include/lldp_dcbx_cmds.h \ @@ -33,7 +33,7 @@ index 893fa45..85ee213 100644 include/lldp_8021qaz_clif.h \ include/lldp_orgspec_clif.h include/lldp_cisco_clif.h \ include/lldptool.h include/lldp_rtnl.h include/dcbtool.h include/lldp_dcbx_cfg.h -@@ -56,19 +56,19 @@ lldp_dcbx.c include/lldp_dcbx.h tlv_dcbx.c include/tlv_dcbx.h \ +@@ -56,19 +56,20 @@ lldp_dcbx.c include/lldp_dcbx.h tlv_dcbx.c include/tlv_dcbx.h \ lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h lldp_util.c \ lldp_mand.c include/lldp_mand.h \ lldp_mand_cmds.c lldp_basman_cmds.c lldp_8023_cmds.c lldp_med_cmds.c \ @@ -56,11 +56,12 @@ index 893fa45..85ee213 100644 -include/lldp_vdp22.h qbg/lldp_vdp22.c qbg/lldp_vdpnl.c +include/lldp_evb22.h lldp_evb22.c lldp_evb22_cmds.c \ +include/qbg22.h include/qbg_ecp22.h qbg/ecp22.c \ -+include/qbg_vdp22.h qbg/vdp22.c qbg/vdpnl.c qbg/vdp22sm.c qbg/vdp22br.c ++include/qbg_vdp22.h qbg/vdp22.c qbg/vdpnl.c qbg/vdp22sm.c qbg/vdp22br.c \ ++include/qbg_vdp22def.h lib_LTLIBRARIES = liblldp_clif.la liblldp_clif_la_LDFLAGS = -version-info 1:0:0 -@@ -83,8 +83,8 @@ dcbtool_LDFLAGS = -ldl -llldp_clif +@@ -83,8 +84,8 @@ dcbtool_LDFLAGS = -ldl -llldp_clif lldptool_SOURCES = lldptool.c lldptool_cmds.c lldp_rtnl.c \ lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c \ lldp_8023_clif.c lldp_dcbx_clif.c lldp_util.c \ @@ -71,7 +72,7 @@ index 893fa45..85ee213 100644 weak_readline.c $(lldpad_include_HEADERS) $(noinst_HEADERS) lldptool_LDADD = ${srcdir}/liblldp_clif.la lldptool_LDFLAGS = -ldl -llldp_clif -@@ -120,25 +120,21 @@ pkgconfig_DATA = lldpad.pc liblldp_clif.pc +@@ -120,25 +121,21 @@ pkgconfig_DATA = lldpad.pc liblldp_clif.pc ## put a spec file and documentation in the distribution archive dist_noinst_DATA = lldpad.spec README COPYING ChangeLog @@ -103,6 +104,19 @@ index 893fa45..85ee213 100644 rm -f '$(includedir)/dcbd/clif_cmds.h' rm -f '$(includedir)/dcbd' +diff --git a/clif.c b/clif.c +index 2984e8e..531305e 100644 +--- a/clif.c ++++ b/clif.c +@@ -240,7 +240,7 @@ pid_t clif_getpid(void) + { + struct clif *clif_conn; + char buf[MAX_CLIF_MSGBUF]; +- size_t len; ++ size_t len = sizeof(buf); + char *ppong; + int ret; + pid_t lldpad = 0; /* LLDPAD process identifier */ diff --git a/config.c b/config.c index 7229b91..36130ad 100644 --- a/config.c @@ -395,7 +409,7 @@ index 687175c..7932c0d 100644 .B lldptool -t -i ethx -V LLDP-MED diff --git a/docs/lldptool.8 b/docs/lldptool.8 -index d076af8..c819700 100644 +index d076af8..e70a712 100644 --- a/docs/lldptool.8 +++ b/docs/lldptool.8 @@ -125,7 +125,7 @@ commands. Configures the LLDP adminStatus parameter for the specified interface @@ -407,6 +421,15 @@ index d076af8..c819700 100644 .TP .B ipv4 +@@ -212,7 +212,7 @@ Get all configured attributes for the Management Address TLV on eth3 + + .TP + Enable transmit of the Edge Virtual Bridging TLV for interface eth4 +-.B lldptool -i eth4 -T -V evbCfg enableTx=yes ++.B lldptool -i eth4 -T -g ncb -V evbCfg enableTx=yes + + .TP + Enable transmit of VDP for interface eth4 diff --git a/event_iface.c b/event_iface.c index 2cd4f0c..297d751 100644 --- a/event_iface.c @@ -966,10 +989,29 @@ index 9f465c4..0000000 -int vdp_uuid2str(const u8 *, char *, size_t); -#endif diff --git a/include/lldp_rtnl.h b/include/lldp_rtnl.h -index 76425e6..6b88db6 100644 +index 76425e6..2bb09b1 100644 --- a/include/lldp_rtnl.h +++ b/include/lldp_rtnl.h -@@ -44,6 +44,6 @@ void mynla_put_u32(struct nlmsghdr *, int, __u32); +@@ -39,11 +39,25 @@ + void mynla_nest_end(struct nlmsghdr *, struct nlattr *); + struct nlattr *mynla_nest_start(struct nlmsghdr *, int); + void mynla_put(struct nlmsghdr *, int, size_t, void *); ++void mynla_put_u8(struct nlmsghdr *, int, __u8); + void mynla_put_u16(struct nlmsghdr *, int, __u16); + void mynla_put_u32(struct nlmsghdr *, int, __u32); ++void mynla_put_s32(struct nlmsghdr *nlh, int type, __s32); ++__u8 mynla_get_u8(const struct nlattr *); ++__u16 mynla_get_u16(const struct nlattr *); ++__u32 mynla_get_u32(const struct nlattr *); ++__s32 mynla_get_s32(const struct nlattr *); ++void mynla_get(const struct nlattr *, size_t, void *); ++void *mynla_data(const struct nlattr *); ++int mynla_payload(const struct nlattr *); ++int mynla_type(const struct nlattr *); ++int mynla_ok(const struct nlattr *, int); ++int mynla_total_size(int); ++struct nlattr *mynla_next(const struct nlattr *, int *); ++int mynla_parse(struct nlattr **, size_t, struct nlattr *, int); int get_operstate(char *ifname); int set_operstate(char *ifname, __u8 operstate); @@ -2033,10 +2075,10 @@ index 0000000..e7de693 +#endif /* _LLDP_VDP_H */ diff --git a/include/qbg_vdp22.h b/include/qbg_vdp22.h new file mode 100644 -index 0000000..6c0ebd2 +index 0000000..aa3d5c5 --- /dev/null +++ b/include/qbg_vdp22.h -@@ -0,0 +1,208 @@ +@@ -0,0 +1,206 @@ +/******************************************************************************* + + Implementation of VDP protocol for IEEE 802.1 Qbg Ratified Standard @@ -2097,34 +2139,13 @@ index 0000000..6c0ebd2 +#include +#include + ++#include ++ +enum vdp22_role { /* State for VDP22 bridge processing */ + VDP22_BRIDGE = 1, /* Bridge role */ + VDP22_STATION /* State role */ +}; + -+/* -+ * Define VDP22 filter info formats. -+ */ -+enum vdp22_ffmt { -+ VDP22_FFMT_VID = 1, -+ VDP22_FFMT_MACVID, -+ VDP22_FFMT_GROUPVID, -+ VDP22_FFMT_GROUPMACVID -+}; -+ -+/* -+ * Define VDP22 VSI Profile modes. -+ */ -+enum vdp22_modes { -+ VDP22_ENDTLV = 0, -+ VDP22_PREASSOC, -+ VDP22_PREASSOC_WITH_RR, -+ VDP22_ASSOC, -+ VDP22_DEASSOC, -+ VDP22_MGRID, -+ VDP22_OUI = 0x7f -+}; -+ +enum vdp22_cmdresp { /* VDP22 Protocol command responses */ + VDP22_RESP_SUCCESS = 0, /* Success */ + VDP22_RESP_INVALID_FORMAT = 1, @@ -2140,14 +2161,7 @@ index 0000000..6c0ebd2 + +enum { + VDP22_MGRIDSZ = 16, /* Size of manager identifier */ -+ VDP22_IDSZ = 16, /* Size of vsi identifier */ -+ VDP22_ID_IP4 = 1, /* VSI ID is IPv4 address */ -+ VDP22_ID_IP6, /* VSI ID is IPv6 address */ -+ VDP22_ID_MAC, /* VSI ID is IEEE 802 MAC address */ -+ VDP22_ID_LOCAL, /* VSI ID is locally defined */ -+ VDP22_ID_UUID, /* VSI ID is RFC4122 UUID */ -+ VDP22_MTOBIT = 16, /* VSI indicate migration to */ -+ VDP22_SUSPBIT = 32 /* VSI indicate migration from */ ++ VDP22_IDSZ = 16 /* Size of vsi identifier */ +}; + +struct vsi_origin { /* Originator of VSI request */ @@ -2163,8 +2177,6 @@ index 0000000..6c0ebd2 + unsigned long grpid; /* Group identifier */ + unsigned char mac[ETH_ALEN]; /* MAC address */ + unsigned short vlan; /* VLAN idenfier */ -+ unsigned char ps; /* PS field */ -+ unsigned char pcp; /* PCP valid when PS true */ + struct vsi_origin requestor; +}; + @@ -2244,6 +2256,115 @@ index 0000000..6c0ebd2 +void vdp22_listdel_vsi(struct vsi22 *); +int vdp22br_resources(struct vsi22 *, int *); +int vdp22_local2str(const u8 *, char *, size_t); ++ ++/* ++ * Functions to get and set vlan identifier and qos. ++ */ ++static inline unsigned short vdp22_get_ps(unsigned short x) ++{ ++ return (x >> 15) & 0x1; ++} ++ ++static inline unsigned short vdp22_get_qos(unsigned short x) ++{ ++ return (x >> 12) & 0xf; ++} ++ ++static inline unsigned short vdp22_set_qos(unsigned short x) ++{ ++ return (x & 0xf) << 12; ++} ++ ++static inline unsigned short vdp22_get_vlanid(unsigned short x) ++{ ++ return x & 0xfff; ++} ++ ++static inline unsigned short vdp22_set_vlanid(unsigned short x) ++{ ++ return (x & 0xfff); ++} ++#endif +diff --git a/include/qbg_vdp22def.h b/include/qbg_vdp22def.h +new file mode 100644 +index 0000000..52f4502 +--- /dev/null ++++ b/include/qbg_vdp22def.h +@@ -0,0 +1,75 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * External interface definition for the ratified standard VDP protocol. ++ */ ++#ifndef QBG_VDP22DEF_H ++#define QBG_VDP22DEF_H ++ ++/* ++ * Define VDP22 filter formats. ++ */ ++enum vdp22_ffmt { /* Format of filter information */ ++ VDP22_FFMT_VID = 1, /* Vlan Identifier */ ++ VDP22_FFMT_MACVID, /* MAC address and Vlan Identifier */ ++ VDP22_FFMT_GROUPVID, /* Group and Vlan Identifier */ ++ VDP22_FFMT_GROUPMACVID /* Group, MAC and Vlan Identifier */ ++}; ++ ++/* ++ * Define VDP22 VSI Profile modes. ++ */ ++enum vdp22_modes { ++ VDP22_ENDTLV = 0, ++ VDP22_PREASSOC = 1, ++ VDP22_PREASSOC_WITH_RR, ++ VDP22_ASSOC, ++ VDP22_DEASSOC, ++ VDP22_MGRID, ++ VDP22_OUI = 0x7f ++}; ++ ++/* ++ * Define VDP22 VSI identifier format ++ */ ++enum vdp22_vsiid_fmt { ++ VDP22_ID_IP4 = 1, /* VSI ID is IPv4 address */ ++ VDP22_ID_IP6, /* VSI ID is IPv6 address */ ++ VDP22_ID_MAC, /* VSI ID is IEEE 802 MAC address */ ++ VDP22_ID_LOCAL, /* VSI ID is locally defined */ ++ VDP22_ID_UUID /* VSI ID is RFC4122 UUID */ ++}; ++ ++ ++/* ++ * Define VDP22 Migiration hints ++ */ ++enum vdp22_migration_hints { ++ VDP22_MIGTO = 16, /* M-bit migrate to hint */ ++ VDP22_MIGFROM = 32 /* S-bit migrate from hint */ ++}; ++ +#endif diff --git a/include/qbg_vdp_clif.h b/include/qbg_vdp_clif.h new file mode 100644 @@ -2339,10 +2460,10 @@ index 0000000..2bbcb1c +#endif diff --git a/include/qbg_vdpnl.h b/include/qbg_vdpnl.h new file mode 100644 -index 0000000..bad6b73 +index 0000000..ece030d --- /dev/null +++ b/include/qbg_vdpnl.h -@@ -0,0 +1,67 @@ +@@ -0,0 +1,78 @@ +/******************************************************************************* + + Implementation of EVB TLVs for LLDP @@ -2379,21 +2500,32 @@ index 0000000..bad6b73 + +#define MAX_PAYLOAD 4096 /* Maximum Payload Size */ + ++enum { ++ vdpnl_nlf1 = 1, /* Netlink message format 1 (draft 0.2) */ ++ vdpnl_nlf2 /* Netlink message format 2 (ratified) */ ++}; ++ +struct vdpnl_mac { /* MAC-VLAN pair */ + unsigned short vlan; /* Vlan identifier */ + unsigned char mac[ETH_ALEN]; /* Mac address */ + unsigned char qos; /* Quality of service */ ++ unsigned char changed; /* Vlan changed by switch */ ++ unsigned long gpid; /* Group identifer */ +}; + +struct vdpnl_vsi { /* Data structure for VSI data via netlink */ -+ char ifname[IFNAMSIZ]; /* Interface name */ ++ char ifname[IFNAMSIZ + 1]; /* Interface name */ + int ifindex; /* Index number */ ++ int vf; /* Virtual function number */ ++ unsigned char hints; /* VSI request mode migrition hints */ + unsigned char request; /* VSI request mode */ + unsigned short response; /* VSI response code */ + unsigned char vsi_mgrid; + unsigned char vsi_typeversion; + unsigned char vsiid_fmt; + unsigned char vsi_uuid[PORT_UUID_MAX]; ++ unsigned char vsi_mgrid2[PORT_UUID_MAX]; ++ unsigned char nl_version; /* Netlink message format version */ + unsigned long vsi_typeid; + unsigned long req_seq; + pid_t req_pid; @@ -7455,10 +7587,117 @@ index 04491de..0000000 - return -1; -} diff --git a/lldp_rtnl.c b/lldp_rtnl.c -index 0c57e62..d4049e2 100644 +index 0c57e62..dffc0ba 100644 --- a/lldp_rtnl.c +++ b/lldp_rtnl.c -@@ -173,7 +173,7 @@ static ssize_t rtnl_send_linkmode(int s, int ifindex, +@@ -75,6 +75,11 @@ void mynla_put(struct nlmsghdr *nlh, int type, size_t len, void *data) + nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(len); + } + ++void mynla_put_u8(struct nlmsghdr *nlh, int type, __u8 data) ++{ ++ mynla_put(nlh, type, sizeof data, &data); ++} ++ + void mynla_put_u16(struct nlmsghdr *nlh, int type, __u16 data) + { + mynla_put(nlh, type, sizeof data, &data); +@@ -85,6 +90,94 @@ void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data) + mynla_put(nlh, type, sizeof data, &data); + } + ++void mynla_put_s32(struct nlmsghdr *nlh, int type, __s32 data) ++{ ++ mynla_put(nlh, type, sizeof data, &data); ++} ++ ++void mynla_get(const struct nlattr *nla, size_t len, void *data) ++{ ++ memcpy(data, mynla_data(nla), len); ++} ++ ++__s32 mynla_get_s32(const struct nlattr *nla) ++{ ++ return *(__u32 *)mynla_data(nla); ++} ++ ++__u32 mynla_get_u32(const struct nlattr *nla) ++{ ++ return *(__u32 *)mynla_data(nla); ++} ++ ++__u16 mynla_get_u16(const struct nlattr *nla) ++{ ++ return *(__u16 *)mynla_data(nla); ++} ++ ++__u8 mynla_get_u8(const struct nlattr *nla) ++{ ++ return *(__u8 *)mynla_data(nla); ++} ++ ++void *mynla_data(const struct nlattr *nla) ++{ ++ return (char *)nla + NLA_HDRLEN; ++} ++ ++int mynla_payload(const struct nlattr *nla) ++{ ++ return nla->nla_len - NLA_HDRLEN; ++} ++ ++int mynla_type(const struct nlattr *nla) ++{ ++ return nla->nla_type & ~NLA_F_NESTED; ++} ++ ++int mynla_ok(const struct nlattr *nla, int rest) ++{ ++ return rest >= (int) sizeof(*nla) && ++ nla->nla_len >= sizeof(*nla) && nla->nla_len <= rest; ++} ++ ++struct nlattr *mynla_next(const struct nlattr *nla, int *rest) ++{ ++ int len = NLA_ALIGN(nla->nla_len); ++ ++ *rest -= len; ++ return (struct nlattr *)((char *)nla + len); ++} ++ ++static inline int mynla_attr_size(int payload) ++{ ++ return NLA_HDRLEN + payload; ++} ++ ++int mynla_total_size(int payload) ++{ ++ return NLA_ALIGN(mynla_attr_size(payload)); ++} ++ ++/* ++ * Parse a list of netlink attributes. ++ * Return 0 on success and errno when the parsing fails. ++ */ ++int mynla_parse(struct nlattr **tb, size_t tb_len, struct nlattr *pos, ++ int attrlen) ++{ ++ unsigned short nla_type; ++ ++ while (mynla_ok(pos, attrlen)) { ++ nla_type = mynla_type(pos); ++ if (nla_type < tb_len) ++ tb[nla_type] = (struct nlattr *)pos; ++ pos = mynla_next(pos, &attrlen); ++ } ++ return (attrlen) ? -EINVAL : 0; ++} ++ ++ + typedef int rtnl_handler(struct nlmsghdr *nh, void *arg); + + /** +@@ -173,7 +266,7 @@ static ssize_t rtnl_send_linkmode(int s, int ifindex, return send(s, &req, req.nh.nlmsg_len, 0); } @@ -7467,7 +7706,7 @@ index 0c57e62..d4049e2 100644 { int s; int rc; -@@ -301,11 +301,6 @@ int get_operstate(char *ifname) +@@ -301,11 +394,6 @@ int get_operstate(char *ifname) return operstate; } @@ -16244,10 +16483,10 @@ index 4a117d6..0000000 -} diff --git a/qbg/vdp.c b/qbg/vdp.c new file mode 100644 -index 0000000..e38375a +index 0000000..f522f91 --- /dev/null +++ b/qbg/vdp.c -@@ -0,0 +1,1905 @@ +@@ -0,0 +1,1906 @@ +/****************************************************************************** + + Implementation of VDP according to IEEE 802.1Qbg @@ -18072,6 +18311,7 @@ index 0000000..e38375a + } + if (ret) { + vdp_trace_profile(p); ++ vsi->macsz = 0; + vsi->response = p->response; + memcpy(vsi->vsi_uuid, p->instance, sizeof vsi->vsi_uuid); + if (p->response != VDP_RESPONSE_NO_RESPONSE @@ -18155,10 +18395,10 @@ index 0000000..e38375a +} diff --git a/qbg/vdp22.c b/qbg/vdp22.c new file mode 100644 -index 0000000..5da593b +index 0000000..6188fbc --- /dev/null +++ b/qbg/vdp22.c -@@ -0,0 +1,917 @@ +@@ -0,0 +1,968 @@ +/****************************************************************************** + + Implementation of VDP22 protocol for IEEE 802.1 Qbg ratified standard @@ -18189,6 +18429,7 @@ index 0000000..5da593b +#include +#include +#include ++#include + +#include + @@ -18261,31 +18502,36 @@ index 0000000..5da593b + for (i = 0; i < no; ++i, ++fe) { + switch (fif) { + case VDP22_FFMT_GROUPVID: -+ LLDPAD_DBG("%s:grpid:%ld vlan:%d ps:%d pcp:%d" ++ LLDPAD_DBG("%s:grpid:%ld vlan:%d qos:%d" + " pid:%d seq:%ld\n", txt, fe->grpid, -+ fe->vlan, fe->ps, fe->pcp, ++ vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), + fe->requestor.req_pid, + fe->requestor.req_seq); + break; + case VDP22_FFMT_GROUPMACVID: + mac2str(fe->mac, idbuf, sizeof idbuf); -+ LLDPAD_DBG("%s:mac:%s grpid:%ld vlan:%d ps:%d" -+ " pcp:%d pid:%d seq:%ld\n", txt, idbuf, -+ fe->grpid, fe->vlan, fe->ps, fe->pcp, ++ LLDPAD_DBG("%s:mac:%s grpid:%ld vlan:%d" ++ " qos:%d pid:%d seq:%ld\n", txt, idbuf, ++ fe->grpid, vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), + fe->requestor.req_pid, + fe->requestor.req_seq); + break; + case VDP22_FFMT_VID: -+ LLDPAD_DBG("%s:vlan:%d ps:%d pcp:%d pid:%d seq:%ld\n", -+ txt, fe->vlan, fe->ps, fe->pcp, ++ LLDPAD_DBG("%s:vlan:%d qos:%d pid:%d seq:%ld\n", ++ txt, vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), + fe->requestor.req_pid, + fe->requestor.req_seq); + break; + case VDP22_FFMT_MACVID: + mac2str(fe->mac, idbuf, sizeof idbuf); -+ LLDPAD_DBG("%s:mac:%s vlan:%d ps:%d pcp:%d" -+ " pid:%d seq:%ld\n", txt, idbuf, fe->vlan, -+ fe->ps, fe->pcp, fe->requestor.req_pid, ++ LLDPAD_DBG("%s:mac:%s vlan:%d qos:%d" ++ " pid:%d seq:%ld\n", txt, idbuf, ++ vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), ++ fe->requestor.req_pid, + fe->requestor.req_seq); + break; + default: @@ -18295,11 +18541,41 @@ index 0000000..5da593b +} + +/* ++ * Convert a mgrid to a printable string. ++ */ ++static void mgrid2str(struct vsi22 *p, char *buf, size_t len) ++{ ++ int i, nul; ++ bool print = false; ++ ++ /* Find last non nul byte */ ++ for (nul = sizeof(p->mgrid) - 1; nul >= 0; --nul) { ++ if (p->mgrid[nul] != '\0') ++ break; ++ } ++ if (nul == 0) { ++ sprintf(buf, "%d", p->mgrid[0]); ++ return; ++ } ++ for (i = 0; i <= nul; ++i) { ++ if (isprint(p->mgrid[i])) ++ print = true; ++ else ++ break; ++ } ++ if (print) ++ strncpy(buf, (char *)p->mgrid, len); ++ else ++ vdp22_local2str(p->mgrid, buf, len); ++} ++ ++/* + * Print VSI data + */ +void vdp22_showvsi(struct vsi22 *p) +{ + char idbuf[VDP_UUID_STRLEN + 2]; ++ char mgridbuf[VDP_UUID_STRLEN + 2]; + + switch (p->vsi_fmt) { + case VDP22_ID_UUID: @@ -18322,11 +18598,12 @@ index 0000000..5da593b + break; + } + ++ mgrid2str(p, mgridbuf, sizeof(mgridbuf)); + LLDPAD_DBG("vsi:%p flags:%#lx vsi_mode:%d,%d status:%#x" + " mgrid:%s id:%ld(%#lx) version:%d" + " id_fmt:%d %s format:%d no:%d\n", + p, p->flags, p->vsi_mode, p->cc_vsi_mode, p->status, -+ p->mgrid, p->type_id, ++ mgridbuf, p->type_id, + p->type_id, p->type_ver, p->vsi_fmt, idbuf, + p->fif, p->no_fdata); + if (p->fdata) @@ -18346,9 +18623,7 @@ index 0000000..5da593b +{ + LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, + p->vsi[0]); -+LLDPAD_DBG("%s:%p no_fdata:%d\n", __func__, p->fdata, p->no_fdata); + free(p->fdata); -+LLDPAD_DBG("%s:%p\n", __func__, p); + free(p); +} + @@ -18527,7 +18802,7 @@ index 0000000..5da593b + switch (fif) { + case VDP22_FFMT_GROUPMACVID: + case VDP22_FFMT_GROUPVID: -+ fp->grpid = 0; /* TODO take from vdpnl */ ++ fp->grpid = from->gpid; + if (fif == VDP22_FFMT_GROUPVID) + goto vid; + /* Fall through intended */ @@ -18537,8 +18812,6 @@ index 0000000..5da593b + case VDP22_FFMT_VID: +vid: + fp->vlan = from->vlan; -+ fp->pcp = from->qos; -+ fp->ps = fp->pcp ? 1 : 0; + break; + } +} @@ -18555,9 +18828,9 @@ index 0000000..5da593b + +static bool check_vid(struct fid22 *fp) +{ -+ if (fp->vlan > 0 && (fp->vlan < 2 || fp->vlan > 4094)) -+ return false; -+ if (fp->pcp & ~7) ++ unsigned short num = vdp22_get_vlanid(fp->vlan); ++ ++ if (num > 0 && (num < 2 || num > 4094)) + return false; + return true; +} @@ -18629,9 +18902,13 @@ index 0000000..5da593b + p->vdp = vdp; + p->vsi_mode = vsi->request; + p->cc_vsi_mode = VDP22_DEASSOC; ++ p->hints = vsi->hints; + p->status = VDP22_RESP_NONE; + p->flags = VDP22_BUSY | VDP22_NLCMD; -+ snprintf((char *)p->mgrid, sizeof(p->mgrid), "%d", vsi->vsi_mgrid); ++ if (vsi->nl_version == vdpnl_nlf2) ++ memcpy(p->mgrid, vsi->vsi_mgrid2, sizeof(p->mgrid)); ++ else ++ p->mgrid[0] = vsi->vsi_mgrid; + p->type_ver = vsi->vsi_typeversion; + p->type_id = vsi->vsi_typeid; + p->vsi_fmt = VDP22_ID_UUID; @@ -18663,6 +18940,7 @@ index 0000000..5da593b + LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, vsi->ifname, p, p->vsi[0]); + return p; +error1: ++ vdp22_showvsi(p); + vdp22_delete_vsi(p); + return NULL; +} @@ -18989,6 +19267,22 @@ index 0000000..5da593b + return mod; +} + ++static void copy_fid(struct vdpnl_vsi *vsi, struct vsi22 *p) ++{ ++ int i; ++ ++ vsi->filter_fmt = p->fif; ++ for (i = 0; i < vsi->macsz; ++i) { ++ if( i == p->no_fdata) ++ break; ++ vsi->maclist[i].gpid = p->fdata[i].grpid; ++ vsi->maclist[i].vlan = vdp22_get_vlanid(p->fdata[i].vlan); ++ vsi->maclist[i].qos = vdp22_get_qos(p->fdata[i].vlan); ++ vsi->maclist[i].changed = 1; ++ } ++ vsi->macsz = i; ++} ++ +/* + * Query a VSI request from buddy and report its progress. Use the interface + * name to determine the VSI profile list. Return one entry in parameter 'vsi' @@ -19024,9 +19318,7 @@ index 0000000..5da593b + memcpy(vsi->vsi_uuid, p->vsi, sizeof(vsi->vsi_uuid)); + p->flags &= ~VDP22_NLCMD; + if (p->flags & VDP22_RETURN_VID) { -+ vsi->maclist->vlan = p->fdata[0].vlan; -+ memcpy(vsi->maclist->mac, p->fdata[0].mac, -+ sizeof(vsi->maclist->mac)); ++ copy_fid(vsi, p); + p->flags &= ~VDP22_RETURN_VID; + } + if (vsi->response != VDP22_RESP_NONE && @@ -19064,7 +19356,6 @@ index 0000000..5da593b + nl.filter_fmt = vsi->fif; + for (i = 0; i < nl.macsz; ++i) { + nlmac[i].vlan = vsi->fdata[i].vlan; -+ nlmac[i].qos = vsi->fdata[i].pcp; + memcpy(nlmac[i].mac, vsi->fdata[i].mac, sizeof(nlmac[i].mac)); + nl.req_pid = vsi->fdata[i].requestor.req_pid; + nl.req_seq = vsi->fdata[i].requestor.req_seq; @@ -19078,10 +19369,10 @@ index 0000000..5da593b + diff --git a/qbg/vdp22br.c b/qbg/vdp22br.c new file mode 100644 -index 0000000..9d5f44d +index 0000000..a3cee9c --- /dev/null +++ b/qbg/vdp22br.c -@@ -0,0 +1,118 @@ +@@ -0,0 +1,189 @@ +/****************************************************************************** + + Implementation of VDP 2.2 bridge resource allocation simulator for LLDP @@ -19160,6 +19451,42 @@ index 0000000..9d5f44d + eloop_register_timeout(35, 0, deassoc, ifname_buf, &deassoc_qbg); + LLDPAD_DBG("%s:%s\n", __func__, vdp->ifname); +} ++ ++static void change_vlan0(struct vsi22 *p, unsigned short idx, int with_qos) ++{ ++ if (p->fif == VDP22_FFMT_MACVID) ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); ++ else ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); ++ if (with_qos) ++ p->fdata[idx].vlan |= vdp22_set_qos(8 + (p->type_ver & 7)); ++} ++ ++static int change_fid(struct vsi22 *p) ++{ ++ unsigned short idx = p->type_ver >> 4 & 0xf; ++ ++ if (idx >= p->no_fdata) ++ return VDP22_RESP_NOADDR; ++ if (p->type_id == 204) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid) ++ | vdp22_set_qos(8 + (p->type_ver & 7)); ++ } else if (p->type_id == 205) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); ++ } else if (p->type_id == 206) { ++ p->fdata[idx].vlan = vdp22_get_vlanid(p->fdata[idx].vlan) ++ | vdp22_set_qos(8 + (p->type_ver & 7)); ++ } else if (p->type_id == 207) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); ++ } else if (p->type_id == 208 && p->fif != VDP22_FFMT_VID) { ++ int i; ++ ++ for (i = 0; i < p->no_fdata; ++i) ++ if (!vdp22_get_vlanid(p->fdata[i].vlan)) ++ change_vlan0(p, i, idx); ++ } ++ return 0; ++} +#endif + +int vdp22br_resources(struct vsi22 *p, int *error) @@ -19175,37 +19502,72 @@ index 0000000..9d5f44d + VDP22_RESP_SUCCESS; +#ifdef BUILD_DEBUG + /* -+ * Trigger errors, type_ver_id determines when fired. ++ * Trigger errors + * Typeid 199 trigger delayed bridge resource availability + * Typeid 200 trigger de-assoc -+ * Typeid 201 trigger error response -+ * Typeid 202 trigger error response with keep bit set ++ * Typeid 201 trigger de-assoc error response ++ * Typeid 202 trigger keep error response with keep bit set ++ * Typeid 203 trigger de-assoc error response with hard bit set ++ * Typeid 199-202 type_ver determines when fired. ++ * ++ * Typeid 204 replace VLAN with groupid as VLAN ID and type_ver as QoS ++ * Typeid 205 replace VLAN 0 with typeid as VLAN ID ++ * Typeid 206 replace QoS 0 with type_ver as QoS ++ * Typeid 207 replace VLAN with groupid as VLAN ID ++ * For typeid 204-207 use upper nipple of type_ver as index into fid ++ * array. ++ * ++ * Typeid 208 replace all VLAN 0 ++ * - with typeid as VLAN ID (filter format MAC/VID) ++ * - with group identifier as VLAN ID (filter format GROUP/[MAC/]VID) ++ * - use upper nibble of type_ver to indicate a QoS change (true), ++ * lower nibble of type_ver is QoS value. + */ -+ if (p->type_id == 199 && called == p->type_ver) { -+ LLDPAD_DBG("%s:%s timeout\n", __func__, p->vdp->ifname); -+ rc = VDP22_RESP_TIMEOUT; -+ } -+ -+ if (p->type_id == 200) ++ switch (p->type_id) { ++ case 199: ++ if (called == p->type_ver) { ++ rc = VDP22_RESP_TIMEOUT; ++ } ++ break; ++ case 200: + trigger_deassoc(p->vdp); -+ else if (p->type_id == 201 && called == p->type_ver) { -+ *error = VDP22_RESP_NO_VSIMGR; -+ rc = VDP22_RESP_DEASSOC; -+ } else if (p->type_id == 202 && called == p->type_ver) { -+ *error = VDP22_RESP_NO_VSIMGR; -+ rc = VDP22_RESP_KEEP; ++ break; ++ case 201: ++ case 203: ++ if (called == p->type_ver) { ++ *error = VDP22_RESP_NO_RESOURCES; ++ rc = VDP22_RESP_DEASSOC; ++ if (p->type_id == 203) ++ *error |= 0x10; ++ } ++ break; ++ case 202: ++ if (called == p->type_ver) { ++ *error = VDP22_RESP_NO_VSIMGR; ++ rc = VDP22_RESP_KEEP; ++ } ++ break; ++ case 204: ++ case 205: ++ case 206: ++ case 207: ++ case 208: ++ *error = change_fid(p); ++ if (*error == VDP22_RESP_NOADDR) ++ rc = VDP22_RESP_DEASSOC; ++ break; + } +#endif -+ LLDPAD_DBG("%s:%s resp_vsi_mode:%d status:%#x\n", __func__, -+ p->vdp->ifname, p->resp_vsi_mode, p->status); ++ LLDPAD_DBG("%s:%s resp_vsi_mode:%d rc:%d error:%d\n", __func__, ++ p->vdp->ifname, p->resp_vsi_mode, rc, *error); + return rc; +} diff --git a/qbg/vdp22sm.c b/qbg/vdp22sm.c new file mode 100644 -index 0000000..e7440da +index 0000000..62fa5a3 --- /dev/null +++ b/qbg/vdp22sm.c -@@ -0,0 +1,1728 @@ +@@ -0,0 +1,1718 @@ +/****************************************************************************** + + Implementation of VDP 2.2 bridge and station state machines for @@ -19363,39 +19725,6 @@ index 0000000..e7440da +static void vdp22_station_info(struct vsi22 *); + +/* -+ * Functions to get and set VLAN, PS and PCP bits. -+ */ -+static inline unsigned short vsi22_get_pcp(unsigned short x) -+{ -+ return (x >> 12) & 7; -+} -+ -+static inline unsigned short vsi22_set_pcp(unsigned short x) -+{ -+ return (x & 7) << 12; -+} -+ -+static inline unsigned short vsi22_get_vlanid(unsigned short x) -+{ -+ return x & 0xfff; -+} -+ -+static inline unsigned short vsi22_set_vlanid(unsigned short x) -+{ -+ return (x & 0xfff); -+} -+ -+static inline unsigned short vsi22_get_ps(unsigned short x) -+{ -+ return (x >> 15) & 1; -+} -+ -+static inline unsigned short vsi22_set_ps(unsigned short x) -+{ -+ return (x & 1) << 15; -+} -+ -+/* + * Return size of packed and unpacked VSI tlv. + */ +static inline size_t mgr22_tlv_sz(void) @@ -19543,25 +19872,23 @@ index 0000000..e7440da + unsigned char fif) +{ + size_t nbytes = 0; -+ unsigned short x = vsi22_set_vlanid(p->vlan) | -+ vsi22_set_pcp(p->pcp) | vsi22_set_ps(p->ps); + + switch (fif) { + case VDP22_FFMT_VID: -+ nbytes = append_2o(cp, x); ++ nbytes = append_2o(cp, p->vlan); + break; + case VDP22_FFMT_MACVID: + nbytes = append_nb(cp, p->mac, sizeof(p->mac)); -+ nbytes += append_2o(cp + nbytes, x); ++ nbytes += append_2o(cp + nbytes, p->vlan); + break; + case VDP22_FFMT_GROUPVID: + nbytes = append_4o(cp, p->grpid); -+ nbytes += append_2o(cp + nbytes, x); ++ nbytes += append_2o(cp + nbytes, p->vlan); + break; + case VDP22_FFMT_GROUPMACVID: + nbytes = append_4o(cp, p->grpid); + nbytes += append_nb(cp + nbytes, p->mac, sizeof(p->mac)); -+ nbytes += append_2o(cp + nbytes, x); ++ nbytes += append_2o(cp + nbytes, p->vlan); + break; + } + return nbytes; @@ -19731,7 +20058,7 @@ index 0000000..e7440da +} + +/* -+ * Station rocessing state, send packed tlvs to bridge. Allocate send buffer ++ * Station processing state, send packed tlvs to bridge. Allocate send buffer + * on stack and create packed TLVs. + */ +static void vdp22st_process(struct vsi22 *vsi) @@ -19784,8 +20111,6 @@ index 0000000..e7440da + " resp_vsi_mode:%d\n", __func__, + vsi->vdp->ifname, vsi, vsi->vsi[0], vsi->flags, + vsi->vsi_mode, vsi->cc_vsi_mode, vsi->resp_vsi_mode); -+ if (vsi->vsi_mode != vsi->resp_vsi_mode && !vsi->status) -+ vsi->status = make_status(VDP22_RESP_OTHER); + vsi->vsi_mode = vsi->cc_vsi_mode = VDP22_DEASSOC; + vsi->flags |= VDP22_DELETE_ME; + vsi->flags &= ~VDP22_BUSY; @@ -20155,15 +20480,19 @@ index 0000000..e7440da + * All fields are compared, even if some are not used. Unused field are + * initialized to zeros and always match. + */ -+static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2) ++static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2, unsigned char fif) +{ -+ bool is_good = (p1->grpid == p2->grpid) -+ && !memcmp(p1->mac, p2->mac, sizeof(p1->mac)); ++ bool is_good = true; + ++ if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) ++ is_good = !memcmp(p1->mac, p2->mac, sizeof(p1->mac)); ++ if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) ++ is_good = (p1->grpid == p2->grpid); + if (is_good) { -+ if (p1->ps) -+ is_good = (p1->pcp == p2->pcp && p1->ps == p2->ps); -+ if (is_good && p1->vlan) ++ if (vdp22_get_vlanid(p1->vlan)) ++ is_good = (vdp22_get_vlanid(p1->vlan) == ++ vdp22_get_vlanid(p2->vlan)); ++ if (is_good && vdp22_get_ps(p1->vlan)) + is_good = (p1->vlan == p2->vlan); + } + return is_good; @@ -20179,8 +20508,10 @@ index 0000000..e7440da + struct fid22 *p1 = &p->fdata[i]; + struct fid22 *p2 = &vsip->fdata[i]; + -+ if (!cmp_fdata1(p1, p2)) ++ if (!cmp_fdata1(p1, p2, p->fif)) { ++ p->status = VDP22_RESP_NOADDR; + return false; ++ } + } + return true; +} @@ -20276,11 +20607,35 @@ index 0000000..e7440da +} + +/* ++ * Test for returned filter information. ++ * Set VDP22_RETURN_VID bit in flags when VLAN id or QoS change is detected. ++ */ ++static void vdp22_cpfid(struct vsi22 *hit, struct vsi22 *from) ++{ ++ int i; ++ struct fid22 *hitm = hit->fdata, *fromm = from->fdata; ++ ++ LLDPAD_DBG("%s:%s no_fdata:%hd,%hd\n", __func__, hit->vdp->ifname, ++ from->no_fdata, hit->no_fdata); ++ if (hit->no_fdata != from->no_fdata) ++ return; ++ for (i = 0; i < hit->no_fdata; ++i, ++hitm, ++fromm) { ++ LLDPAD_DBG("%s:%s vlan:%#hx,%#hx\n", __func__, ++ hit->vdp->ifname, hitm->vlan, fromm->vlan); ++ if (hitm->vlan != fromm->vlan) { ++ hitm->vlan = fromm->vlan; ++ hit->flags |= VDP22_RETURN_VID; ++ } ++ } ++ LLDPAD_DBG("%s:%s flags:%#lx\n", __func__, hit->vdp->ifname, ++ hit->flags); ++} ++ ++/* + * Input from bridge side. + * + * NOTE: + * - Parameter vsip and associated fid data is on stack memory. -+ * - New filter information data assigned to new_fdata/new_no_fdata. + */ +static void vdp22_bridge_info(struct vsi22 *vsip) +{ @@ -20308,9 +20663,7 @@ index 0000000..e7440da + if (vdp22_cmp_fdata(hit, vsip)) { + hit->smi.resp_ok = true; + hit->resp_vsi_mode = vsip->vsi_mode; /* Take response */ -+ if (hit->flags & VDP22_RETURN_VID) -+ LLDPAD_DBG("%s:%s TODO return vid + qos\n", __func__, -+ vsip->vdp->ifname); ++ vdp22_cpfid(hit, vsip); /* Take filter */ + if (hit->cc_vsi_mode != VDP22_DEASSOC + && (hit->resp_vsi_mode == VDP22_DEASSOC + || bad_error(hit->status)) @@ -20366,9 +20719,6 @@ index 0000000..e7440da + offset += extract_2o(&fidp->vlan, cp + offset); + break; + } -+ fidp->pcp = vsi22_get_pcp(fidp->vlan); -+ fidp->ps = vsi22_get_ps(fidp->vlan); -+ fidp->vlan = vsi22_get_vlanid(fidp->vlan); + return offset; +} + @@ -20634,16 +20984,17 @@ index 0000000..e7440da + LLDPAD_DBG("%s:%s vsi:%p(%02x) id:%ld\n", __func__, + p->vdp->ifname, p, p->vsi[0], p->type_id); + vdp22br_start_restimer(p); ++ p->status = 0; + p->resp_vsi_mode = VDP22_RESP_SUCCESS; + rc = vdp22br_resources(p, &error); + switch (rc) { + case VDP22_RESP_TIMEOUT: + break; + case VDP22_RESP_KEEP: -+ p->status = VDP22_KEEPBIT | make_status(error); ++ p->status = VDP22_KEEPBIT; + goto rest; + case VDP22_RESP_DEASSOC: -+ if (error > (1 << VDP22_STATUS_SHIFT)) ++ if (error >= (1 << VDP22_STATUS_SHIFT)) + p->status = VDP22_HARDBIT; + /* Fall through intended */ + case VDP22_RESP_SUCCESS: @@ -20745,6 +21096,7 @@ index 0000000..e7440da + break; + case VDP22_BR_WAITCMD: + assert(p->smi.state == VDP22_BR_SEND ++ || p->smi.state == VDP22_BR_KEEP + || p->smi.state == VDP22_BR_ALIVE); + break; + case VDP22_BR_WAITCMD_2: @@ -20867,7 +21219,7 @@ index 0000000..e7440da + vdp22br_reply(p); + break; + case VDP22_BR_KEEP: -+ vdp22br_sendack(p, VDP22_KEEPBIT); ++ vdp22br_sendack(p, p->status); + break; + case VDP22_BR_DEASSOC: + vdp22br_deassoc(p, p->status); @@ -21773,10 +22125,10 @@ index 0000000..95bcfb1 +} diff --git a/qbg/vdpnl.c b/qbg/vdpnl.c new file mode 100644 -index 0000000..a2a381f +index 0000000..61b6a2b --- /dev/null +++ b/qbg/vdpnl.c -@@ -0,0 +1,523 @@ +@@ -0,0 +1,527 @@ +/****************************************************************************** + + Implementation of VDP according to IEEE 802.1Qbg @@ -22139,26 +22491,30 @@ index 0000000..a2a381f +static int vdpnl_getlink(struct nlmsghdr *nlh, size_t len) +{ + struct vdpnl_vsi p; ++ struct vdpnl_mac mac; + int i = 0, rc; + struct nlattr *vf_ports, *vf_port; + + memset(&p, 0, sizeof p); ++ memset(&mac, 0, sizeof mac); ++ p.macsz = 1; ++ p.maclist = &mac; + rc = vdpnl_get(nlh, &p); + if (rc) + return vdpnl_error(rc, nlh, len); + vdpnl_reply1(&p, nlh, len); + vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -+ vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); + /* Iterate over all profiles */ + do { + rc = vdp22_query(p.ifname) ? vdp22_status(++i, &p) + : vdp_status(++i, &p); -+ if (rc == 1) ++ if (rc == 1) { ++ vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); + vdpnl_reply2(&p, nlh); -+ if (rc == 0) { + mynla_nest_end(nlh, vf_port); -+ mynla_nest_end(nlh, vf_ports); + } ++ if (rc == 0) ++ mynla_nest_end(nlh, vf_ports); + } while (rc == 1); + if (rc < 0) + return vdpnl_error(rc, nlh, len); @@ -22423,10 +22779,143 @@ index 7ace3b1..da05463 100644 } diff --git a/test/vdptest.1 b/test/vdptest.1 -index 81a2e60..cbdb8dd 100644 +index 81a2e60..5f1a1b9 100644 --- a/test/vdptest.1 +++ b/test/vdptest.1 -@@ -272,12 +272,12 @@ Several definitions using the same +@@ -1,5 +1,5 @@ + .PU +-.TH vdptest 1 "LLDPAD" "Revision: 0.1" ++.TH vdptest 1 "LLDPAD" "Revision: 0.2" + .SH NAME + vdptest \- VDP/VSI Protocol Test Program for LLDPAD + .SH SYNOPSIS +@@ -89,12 +89,16 @@ terminates. + .br + .B vdptest + should be used for testing and debug purposes only. ++It should be noted that there is no state stored in vdptest between calls, but ++will be stored in lldpad (until the process restarts). ++A profile must be created and acted upon on in the same vdptest command. + .SS Profiles + .br + Profile is a comma separated list of key '=' value + pairs describing the VSI profile data. + Profiles consists of the following keywords, +-they are all mandatory: ++they are all mandatory with the execption of ++hints: + .TP + name: + Defines the name of the entry. +@@ -105,10 +109,20 @@ starting + with a character. + .TP + mgrid: +-Defines the manager identifier for this entry. ++Defines the 1 byte manager identifier for this entry ++as defined by the IEEE 802.1 Qbg draft version 0.2. + The value should be a number in the + range of 0..255 inclusive. + .TP ++2mgrid: ++Defines the 16 byte manager identifier for this entry ++as defined by the IEEE 802.1 Qbg ratified standard. ++Either the ++.B mgrid ++or the ++.B 2mgrid ++should be used for an entry. ++.TP + typeid: + Defines the type identifier for this entry. + The value should be a number in the +@@ -130,26 +144,77 @@ The string is converted into 16 byte UUID + with 2 nibbles converted into one byte. + .TP + map: +-Defines a VLAN-MAC address pair for this entry. ++Defines a VLAN-MAC-GROUP address triple for this entry. + The value is of the following format: + .EX +-vlanid-aa:bb:cc:dd:ee:ff ++vlanid[/newvid][-[aa:bb:cc:dd:ee:ff][-grid]] + .EE + Vlandid is converted into a number ranging +-from 0..4095. +-Following the vlanid is a dash (\-) and +-an MAC address. ++from 0..65535. ++If the vlanid is followed by an option slash ('/') ++the number following the slash is the new vlan identifier ++expected from the switch. ++Following the vlanid is an optional dash (\-) and ++a MAC address. + The MAC address is a 6 byte value, each byte + delimited by a colon (':'). ++A second optional dash (\-) can be ++specified to supply a group identifier. ++If omitted the group identifier is assumed to ++be zero and is ignored. + This keyword can be listed several times to allow +-multiple MAC-VLAN pairs per entry. ++multiple MAC-VLAN-GROUP triples per entry. ++.sp 1 ++The form of this entry determines the format of the ++filter information data send to the switch. ++The input ++.EX ++map=1 ++.EE ++is converted to filter information format ++.IR VID . ++The input ++.EX ++map=1--123 ++.EE ++is converted to filter information format ++.IR GROUP/VID . ++The input ++.EX ++map=1-11:22:33:44:55:66 ++.EE ++is converted to filter information format ++.IR VID/MAC . ++The input ++.EX ++map=1-11:22:33:44:55:66-123 ++.EE ++is converted to filter information format ++.IR GROUP/VID/MAC . ++Note that filter information formats can not be mixed in ++a single entry. Multiple ++map entries have to be of the same format. ++.TP ++hints: ++This keyword is optional and if omitted defaults to ++.IR none . ++Indicates support for IEEE 802.1 Qbg ratified standard ++virtual machine migration. ++Valid keywords are ++.I none ++(no indicate no migration support), ++.I to ++(to indicate the virtual machine is migrating to this VSI) ++and ++.I from ++(to indicate the virtual machine is migrating from this VSI). + .TP + Example: + Here is an example of a profile definition: + .EX +-name=thomas2,mgrid=1,typeid=123452,typeidver=1,\(rs ++name=thomas2,mgrid=1,typeid=123452,typeidver=1,hints=none\(rs + uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,\(rs +- map=2-52:54:00:8e:50:53 ++ map=2-52:54:00:8e:50:53-9999,map=0/10-52:54:00:8e:50:54-8888 + .EE + .SS Commands + Command is an option character followed +@@ -272,12 +337,12 @@ Several definitions using the same .I name are not allowed. .TP @@ -22443,7 +22932,7 @@ index 81a2e60..cbdb8dd 100644 are to be changed using the same syntax as in the profile definition. If an error is encountered during keyword parsing -@@ -401,15 +401,11 @@ flag. If this option is not set then the following default values +@@ -401,15 +466,11 @@ flag. If this option is not set then the following default values are used: delaytime (1 second), waittime (1 second) and number of acknowledgements reads (1). .SH "EXAMPLES" @@ -22461,7 +22950,7 @@ index 81a2e60..cbdb8dd 100644 .EE .sp 1 Copies the entry named -@@ -425,7 +421,7 @@ is the +@@ -425,7 +486,7 @@ is the field. .sp 1 .EX @@ -22470,7 +22959,14 @@ index 81a2e60..cbdb8dd 100644 .EE .sp 1 Use interface eth2 and read the VSI configuration from file -@@ -438,8 +434,7 @@ times and expected the error code 3 from the switch. +@@ -434,12 +495,13 @@ Use the VSI definition named + .I unknown + and send an ASSOCIATION command to the switch. + Wait up to 10 seconds for the status confirmation 2 +-times and expected the error code 3 from the switch. ++times and expected the error code 3 from the switch ++(NOTE that this will cause vdptest to return FAILURE under ++normal conditions). Wait one second before termintation. .sp 1 .EX @@ -22480,17 +22976,18 @@ index 81a2e60..cbdb8dd 100644 .EE .sp 1 Use interface eth2 and read the VSI configuration from file -@@ -455,12 +450,15 @@ Send an ASSOCIATION command with parameters stored in +@@ -455,12 +517,17 @@ Send an ASSOCIATION command with parameters stored in wait one second and send an ASSOCIATION command with parameters stored in .IR x1 . --.SH FILES --/var/run/lldpad.pid +.sp 1 +.EX +vdptest -i eth2 -F vdptest.cfg -Cnew=x1,name=thomas2,2mgrid=blabla \(rs + -a thomas2,w=10,r=2,e=3 -s -a x1,w=5 +.EE + .SH FILES +-/var/run/lldpad.pid ++/var/run/lldpad.pid, /var/lib/lldpad/lldpad.conf .SH "ENVIRONMENT" -Linux RHEL +Linux @@ -22501,10 +22998,234 @@ index 81a2e60..cbdb8dd 100644 Exit status is zero on success and non zero on failure or mismatch. .SH AUTHOR diff --git a/test/vdptest.c b/test/vdptest.c -index 8447c6c..59bc812 100644 +index 8447c6c..e93fed0 100644 --- a/test/vdptest.c +++ b/test/vdptest.c -@@ -858,7 +858,7 @@ static int check_typeid(char *value, struct vdpdata *profile) +@@ -67,21 +67,38 @@ + #define CMD_EXTERN 'E' /* External command */ + #define CMD_SETDF 'X' /* Change defaults */ + ++#define FIF_VID 1 /* Vlan id */ ++#define FIF_VIDMAC 2 /* Vlan+mac id */ ++#define FIF_GRPVID 3 /* Group+Vlan id */ ++#define FIF_GRPVIDMAC 4 /* group+Vlan+mac id */ ++ ++#define MIGTO 16 /* M-bit migrate to indicator */ ++#define MIGFROM 32 /* S-bit migrate from indicator */ ++ + /* + * Set the define MYDEBUG to any value for detailed debugging + */ + ++enum { /* Netlink message format for lldpad */ ++ nlmsg_v0 = 1, /* IEEE 802.1 QBG version 0.2 */ ++ nlmsg_v2 /* IEEE 802.1 QBG version 2.2 */ ++}; ++ + enum { + f_map, + f_mgrid, + f_typeid, + f_typeidver, +- f_uuid ++ f_uuid, ++ f_hints, ++ f_2mgrid + }; + + struct macvlan { + unsigned char mac[ETH_ALEN]; /* MAC address */ +- unsigned short vlanid; /* VLAN Id */ ++ unsigned short vlanid; /* VLAN Id */ ++ unsigned long gpid; /* Group */ ++ unsigned short newvid; /* New vlan id returned from switch */ + }; + + static struct vdpdata { +@@ -92,7 +109,11 @@ static struct vdpdata { + unsigned char typeidver; /* Type ID version */ + unsigned int typeid; /* Type ID */ + unsigned char uuid[UUIDLEN]; /* Instance ID */ ++ unsigned char mgrid2[UUIDLEN]; /* Manager ID VDP22 */ + struct macvlan addr[10]; /* Pairs of MAC/VLAN */ ++ unsigned char fif; /* Filter info format */ ++ unsigned char hints; /* Migrate to/from hits */ ++ unsigned char nlmsg_v; /* Version of netlink messaage to use */ + } vsidata[32]; + + static struct command { /* Command structure */ +@@ -483,6 +504,8 @@ static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd) + op = PORT_REQUEST_PREASSOCIATE_RR; + break; + } ++ if (vdp->hints) ++ op |= vdp->hints; + + vsi.vsi_mgr_id = vdp->mgrid; + vsi.vsi_type_version = vdp->typeidver; +@@ -505,6 +528,9 @@ static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd) + return 0; + } + ++/* ++ * Add filter information and use SPOOFCHK to send group information ++ */ + static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) + { + int i; +@@ -518,7 +544,7 @@ static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) + if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO))) + return -ENOMEM; + +- if (vdp->addr[i].mac) { ++ if (vdp->fif == FIF_VIDMAC || vdp->fif == FIF_GRPVIDMAC) { + struct ifla_vf_mac ifla_vf_mac; + + ifla_vf_mac.vf = PORT_SELF_VF; +@@ -528,11 +554,11 @@ static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) + return -ENOMEM; + } + +- if (vdp->addr[i].vlanid) { ++ if (vdp->fif) { + struct ifla_vf_vlan ifla_vf_vlan = { + .vf = PORT_SELF_VF, +- .vlan = vdp->addr[i].vlanid, +- .qos = 0, ++ .vlan = vdp->addr[i].vlanid & 0xfff, ++ .qos = (vdp->addr[i].vlanid >> 12) & 7 + }; + + if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof ifla_vf_vlan, +@@ -759,37 +785,78 @@ static struct vdpdata *nextfree() + + static int check_map(char *value, struct vdpdata *profile) + { +- char *delim = strchr(value, '-'); +- unsigned long vlan; +- int i, ec, x[ETH_ALEN]; ++ char *delim2 = 0, *slash, *delim = strchr(value, '-'); ++ unsigned long vlan, newvlan = 0, gpid = 0; ++ int fif, i, ec, x[ETH_ALEN]; ++ int have_mac = 1, have_gpid = 1; + +- if (!delim) { +- fprintf(stderr, "%s invalid map format %s\n", progname, value); +- return -1; ++ if (!delim) ++ have_gpid = have_mac = 0; ++ else { ++ *delim = '\0'; ++ delim2 = strchr(delim + 1, '-'); ++ if (!delim2) ++ have_gpid = 0; ++ else { ++ *delim2 = '\0'; ++ if (delim + 1 == delim2) /* -- and no mac */ ++ have_mac = 0; ++ } ++ } ++ memset(x, 0, sizeof(x)); ++ slash = strchr(value, '/'); ++ if (slash) { /* Expect replacement vid */ ++ *slash = '\0'; ++ newvlan = getnumber("map", slash + 1, '\0', &ec); ++ if (ec) { ++ fprintf(stderr, "%s invalid new vlanid %s\n", progname, ++ value); ++ return -1; ++ } ++ if (newvlan >= 0x10000) { ++ fprintf(stderr, "%s new vlanid %ld too high\n", ++ progname, newvlan); ++ return -1; ++ } ++ profile->nlmsg_v = nlmsg_v2; + } +- vlan = getnumber("map", value, '-', &ec); ++ vlan = getnumber("map", value, '\0', &ec); + if (ec) { + fprintf(stderr, "%s invalid vlanid %s\n", progname, value); + return -1; + } +- if (vlan >= 4095) { ++ if (vlan >= 0x10000) { + fprintf(stderr, "%s vlanid %ld too high\n", progname, vlan); + return -1; + } +- ++delim; +- ec = sscanf(delim, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0], &x[1], +- &x[2], &x[3], &x[4], &x[5]); +- if (ec != ETH_ALEN) { +- fprintf(stderr, "%s mac %s invalid\n", progname, delim); +- return -1; ++ fif = FIF_VID; ++ if (have_mac) { ++ ec = sscanf(delim + 1, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0], ++ &x[1], &x[2], &x[3], &x[4], &x[5]); ++ if (ec != ETH_ALEN) { ++ fprintf(stderr, "%s mac %s invalid\n", progname, delim); ++ return -1; ++ } ++ /* Check for last character */ ++ delim = strrchr(delim + 1, ':') + 2; ++ if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 ++ || *(delim + 1) != '\0')) { ++ fprintf(stderr, "%s last mac part %s invalid\n", ++ progname, delim); ++ return -1; ++ } ++ fif = FIF_VIDMAC; + } +- /* Check for last character */ +- delim = strrchr(value, ':') + 2; +- if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 +- || *(delim + 1) != '\0')) { +- fprintf(stderr, "%s last mac part %s invalid\n", progname, +- delim); +- return -1; ++ /* Check for optional group identifier */ ++ if (have_gpid && *(delim2 + 1)) { ++ gpid = getnumber("group", delim2 + 1, '\0', &ec); ++ if (ec) { ++ fprintf(stderr, "%s invalid groupid %s\n", progname, ++ delim2 + 1); ++ return -1; ++ } ++ fif += 2; ++ profile->nlmsg_v = nlmsg_v2; + } + #ifdef MYDEBUG + for (i = 0; i < ETH_ALEN; ++i) +@@ -797,7 +864,18 @@ static int check_map(char *value, struct vdpdata *profile) + puts(""); + + #endif ++ if (profile->fif && profile->fif != fif) { ++ fprintf(stderr, "%s invalid filter info format %d use %d\n", ++ progname, FIF_VIDMAC, profile->fif); ++ return -1; ++ } ++ profile->fif = fif; + for (ec = 0; ec < profile->pairs; ++ec) { ++ if (DIM(profile->addr) == i) { ++ fprintf(stderr, "%s too many mac addresses\n", ++ progname); ++ return -1; ++ } + for (i = 0; i < ETH_ALEN; ++i) + if (profile->addr[ec].mac[i] != x[i]) + break; +@@ -809,6 +887,8 @@ static int check_map(char *value, struct vdpdata *profile) + } + ec = profile->pairs++; + profile->addr[ec].vlanid = vlan; ++ profile->addr[ec].newvid = newvlan; ++ profile->addr[ec].gpid = gpid; + for (i = 0; i < ETH_ALEN; ++i) + profile->addr[ec].mac[i] = x[i]; + profile->modified |= 1 << f_map; +@@ -858,7 +938,7 @@ static int check_typeid(char *value, struct vdpdata *profile) progname, no); } #ifdef MYDEBUG @@ -22513,7 +23234,7 @@ index 8447c6c..59bc812 100644 #endif } return ec; -@@ -880,7 +880,8 @@ static int check_typeidversion(char *value, struct vdpdata *profile) +@@ -880,7 +960,8 @@ static int check_typeidversion(char *value, struct vdpdata *profile) progname, no); } #ifdef MYDEBUG @@ -22523,3 +23244,207 @@ index 8447c6c..59bc812 100644 #endif } return ec; +@@ -891,11 +972,17 @@ static int check_mgrid(char *value, struct vdpdata *profile) + unsigned long no; + int ec; + ++ if (profile->nlmsg_v == nlmsg_v2) { ++ fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname); ++ return -1; ++ } + no = getnumber("mgrid", value, '\0', &ec); + if (!ec) { +- if (no <= 255) { ++ if (no <= 255 && no > 0) { ++ profile->nlmsg_v = nlmsg_v0; + profile->mgrid = no; + profile->modified |= 1 << f_mgrid; ++ memset(profile->mgrid2, 0, UUIDLEN); + } else { + ec = -1; + fprintf(stderr, "%s: invalid mgrid %ld\n", progname, +@@ -908,6 +995,44 @@ static int check_mgrid(char *value, struct vdpdata *profile) + return ec; + } + ++static int check_2mgrid(char *value, struct vdpdata *profile) ++{ ++ if (profile->nlmsg_v == nlmsg_v0) { ++ fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname); ++ return -1; ++ } ++ strncpy((char *)profile->mgrid2, value, UUIDLEN - 1); ++ profile->mgrid2[UUIDLEN - 1] = '\0'; ++ profile->mgrid = 0; ++ profile->modified |= 1 << f_mgrid; ++ profile->nlmsg_v = nlmsg_v2; ++ return 0; ++} ++ ++static int check_hints(char *value, struct vdpdata *profile) ++{ ++ int rc = 0; ++ ++ if (!strcmp(value, "to")) { ++ profile->hints = MIGTO; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = nlmsg_v2; ++ } else if (!strcmp(value, "from")) { ++ profile->hints = MIGFROM; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = nlmsg_v2; ++ } else if (!strcmp(value, "none")) { ++ profile->hints = 0; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = nlmsg_v2; ++ } else { ++ fprintf(stderr, "%s: invalid hints %s\n", progname, value); ++ rc = -1; ++ } ++ return rc; ++} ++ ++ + /* + * Return true if the character is valid for a key + */ +@@ -956,7 +1081,9 @@ static char *keytable[] = { + "typeidver", + "typeid", + "uuid", +- "name" ++ "name", ++ "2mgrid", ++ "hints" + }; + + static int findkeyword(char *word) +@@ -995,6 +1122,12 @@ static int checkword(char *word, char *value, struct vdpdata *profile) + case 5: + rc = check_name(value, profile); + break; ++ case 6: ++ rc = check_2mgrid(value, profile); ++ break; ++ case 7: ++ rc = check_hints(value, profile); ++ break; + } + #ifdef MYDEBUG + printf("%s word:%s value:%s rc:%d\n", __func__, word, value, rc); +@@ -1034,14 +1167,20 @@ static int has_key(struct vdpdata *found) + static void print_pairs(struct vdpdata *found) + { + int i; +- char buf[32]; + + for (i = 0; i < found->pairs; ++i) { +- unsigned char *xp = found->addr[i].mac; +- +- sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", +- xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); +- printf("\t%hd %s\n", found->addr[i].vlanid, buf); ++ printf("\t%hd", found->addr[i].vlanid); ++ if (found->addr[i].newvid) ++ printf("/%hd", found->addr[i].newvid); ++ if (found->fif == FIF_VIDMAC || found->fif == FIF_GRPVIDMAC) { ++ unsigned char *xp = found->addr[i].mac; ++ ++ printf(" %02x:%02x:%02x:%02x:%02x:%02x", ++ xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); ++ } ++ if (found->fif == FIF_GRPVID || found->fif == FIF_GRPVIDMAC) ++ printf(" %ld", found->addr[i].gpid); ++ printf("\n"); + } + } + +@@ -1049,8 +1188,16 @@ static void print_profile(struct vdpdata *found) + { + char uuid[64]; + +- printf("key:%s mgrid:%d typeid:%#x typeidver:%d\n", +- found->key, found->mgrid, found->typeid, found->typeidver); ++ if (found->mgrid) ++ sprintf(uuid, "%d", found->mgrid); ++ else ++ strcpy(uuid, (char *)found->mgrid2); ++ printf("key:%s version:%d fif:%d mgrid:%s typeid:%#x typeidver:%d", ++ found->key, found->nlmsg_v, found->fif, uuid, found->typeid, ++ found->typeidver); ++ if (found->hints) ++ printf(" hints:%s", found->hints == MIGTO ? "to" : "from"); ++ printf("\n"); + uuid2buf(found->uuid, uuid); + printf("\tuuid:%s\n", uuid); + if (found->pairs) +@@ -1063,17 +1210,23 @@ static int change_profile(struct vdpdata *change, struct vdpdata *alter) + printf("%s alter->modified:%#x\n", __func__, alter->modified); + #endif + if ((alter->modified & (1 << f_map))) { ++ change->fif = alter->fif; + change->pairs = alter->pairs; + memcpy(change->addr, alter->addr, sizeof alter->addr); + } +- if ((alter->modified & (1 << f_mgrid))) ++ if ((alter->modified & (1 << f_mgrid))) { + change->mgrid = alter->mgrid; ++ memcpy(change->mgrid2, alter->mgrid2, UUIDLEN); ++ } + if ((alter->modified & (1 << f_typeid))) + change->typeid = alter->typeid; + if ((alter->modified & (1 << f_typeidver))) + change->typeidver = alter->typeidver; + if ((alter->modified & (1 << f_uuid))) + memcpy(change->uuid, alter->uuid, sizeof change->uuid); ++ if ((alter->modified & (1 << f_hints))) ++ change->hints = alter->hints; ++ change->nlmsg_v = alter->nlmsg_v; + return 0; + } + +@@ -1094,7 +1247,7 @@ static void show_profiles(char *thisone) + + /* + * Parse the profile string of the form +- * key=###,mgrid=###,typeid=###,typeidver=###,uuid=###,mac=xxx,vlan=xxx{1,10} ++ * key=###,mgrid=###|2mgrid=xxx,typeid=###,typeidver=###,uuid=xxx,map=xxx{1,10} + */ + static int parse_profile(char *profile, struct vdpdata *target) + { +@@ -1158,15 +1311,21 @@ static void find_field(unsigned char mode, char *buf) + strcat(buf, ","); + strcat(buf, "uuid"); + } ++ if ((mode & (1 << f_hints)) == 0) { ++ if (comma) ++ strcat(buf, ","); ++ strcat(buf, "hints"); ++ } + } + + static void isvalid_profile(struct vdpdata *vdp) + { + char buf[64]; + unsigned char mode = 1 << f_map | 1 << f_mgrid | +- 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; ++ 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; ++ unsigned char optmode = 1 << f_hints; + +- if (vdp->modified != mode) { ++ if ((vdp->modified & ~optmode) != mode) { + find_field(vdp->modified, buf); + fprintf(stderr, "%s key %s misses profile fields %s\n", + progname, vdp->key, buf); +@@ -1199,6 +1358,11 @@ static int make_profiles(char *profile, char *newkey) + progname, nextone.key); + return -1; + } ++ if (!strcmp(newkey, found->key)) { ++ fprintf(stderr, "%s profile key %s already exits\n", ++ progname, newkey); ++ return -1; ++ } + if (!(vdp = nextfree())) { + fprintf(stderr, "%s too many profiles\n", progname); + return -1; diff --git a/open-lldp.changes b/open-lldp.changes index 71ea763..a5207ba 100644 --- a/open-lldp.changes +++ b/open-lldp.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Tue Nov 19 12:52:45 CET 2013 - hare@suse.de + +- Update to latest git version: + * VPD22 support + * Netlink fixes + ------------------------------------------------------------------- Thu Oct 10 15:14:39 UTC 2013 - tchvatal@suse.com From f758300030e78fe93e29485daa7841f2bbca4de676e175e5e428c7c3b9713685 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 26 Nov 2013 10:21:50 +0000 Subject: [PATCH 2/2] Accepting request 208479 from home:gabi2 removed 'chmod 655 %{buildroot}' from spec-file OBS-URL: https://build.opensuse.org/request/show/208479 OBS-URL: https://build.opensuse.org/package/show/network:fcoe/open-lldp?expand=0&rev=10 --- open-lldp.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/open-lldp.spec b/open-lldp.spec index 0acba91..03fff24 100644 --- a/open-lldp.spec +++ b/open-lldp.spec @@ -94,7 +94,6 @@ install -m 755 %{S:22} %{buildroot}/lib/mkinitrd/scripts/setup-lldpad.sh # remove la archives rm -rf %{buildroot}/%{_libdir}/*.la ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rclldpad -chmod 655 %{buildroot}/ %post [ -x /sbin/mkinitrd_setup ] && mkinitrd_setup